Это должно сделать это:
CREATE OR REPLACE FUNCTION device_bid_modifiers_count_per()
RETURNS TRIGGER AS
$func$
DECLARE
devices_count int := device_types_count();
table_name regclass := TG_ARGV[0];
column_name text := TG_ARGV[1];
BEGIN
LOCK TABLE device_types IN EXCLUSIVE MODE;
EXECUTE format('LOCK TABLE %s IN EXCLUSIVE MODE', table_name);
IF TG_OP = 'DELETE' THEN
PERFORM validate_bid_modifiers_count(table_name
, column_name
, (row_to_json(OLD) ->> column_name)::bigint
, devices_count);
ELSE
PERFORM validate_bid_modifiers_count(table_name
, column_name
, (row_to_json(NEW) ->> column_name)::bigint
, devices_count);
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Непосредственной причиной сообщения об ошибке была внешняя SELECT
. Без цели вам нужно заменить ее на PERFORM
в plpgsql. Но внутреннее PERFORM
в строке запроса, переданной EXECUTE
, тоже было неверным. PERFORM
- это команда plpgsql, недопустимая в строке SQL, переданной в EXECUTE
, которая ожидает код SQL. Вы должны использовать SELECT
там. Наконец, OLD
и NEW
не видны внутри EXECUTE
, и каждый из них вызовет свое собственное исключение, как у вас. Все проблемы устранены путем удаления EXECUTE
.
Простой и быстрый способ получить значение динамического имени столбца из типов строк OLD
и NEW
: приведение к json
, затем вы можете параметризовать имя ключа, как показано , Должно быть немного проще и быстрее, чем альтернатива с динамическим SQL - что также возможно, например:
...
EXECUTE format('SELECT validate_bid_modifiers_count(table_name
, column_name
, ($1.%I)::bigint
, devices_count)', column_name)
USING OLD;
...
Связанный:
В стороне: не уверен, зачем нужны тяжелые блокировки.
В сторону 2: рассмотрите возможность написания отдельной функции триггера для каждого триггера. Более шумный DDL, но проще и быстрее для выполнения.
Вот то, как
int i = Math.Abs(386792);
while(i >= 10)
i /= 10;
и i
будет содержать то, в чем Вы нуждаетесь
Вот более простой путь, который не включает цикличное выполнение
int number = 1234
int firstDigit = Math.Floor(number/(Math.Pow(10, number.ToString().length - 1))
Это дало бы нам 1234/математика. Голова (10, 4 - 1) = 1234/1000 = 1
int start = curr;
while (start >= 10)
start /= 10;
Это более эффективно, чем ToString () подход, который внутренне должен реализовать подобный цикл и должен создать (и синтаксический анализ) строковый объект на пути...
start = getFirstDigit(start);
public int getFirstDigit(final int start){
int number = Math.abs(start);
while(number > 10){
number /= 10;
}
return number;
}
или
public int getFirstDigit(final int start){
return getFirstDigit(Math.abs(start), true);
}
private int getFirstDigit(final int start, final boolean recurse){
if(start < 10){
return start;
}
return getFirstDigit(start / 10, recurse);
}
Не повторяющаяся формула:
public static int GetHighestDigit(int num)
{
if (num <= 0)
return 0;
return (int)((double)num / Math.Pow(10f, Math.Floor(Math.Log10(num))));
}
Только, чтобы дать Вам альтернативу, Вы могли неоднократно делить целое число на 10 и затем откатывать одно значение, после того как Вы достигаете нуля. Так как строковые операции являются обычно медленными, это может быть быстрее, чем обработка строк, но ни в коем случае не изящно.
Что-то вроде этого:
while(curr>=10)
curr /= 10;
while (i > 10)
{
i = (Int32)Math.Floor((Decimal)i / 10);
}
// i is now the first int
Очень простой (и вероятно довольно быстро, потому что это только включает сравнения и одно подразделение):
if(i<10)
firstdigit = i;
else if (i<100)
firstdigit = i/10;
else if (i<1000)
firstdigit = i/100;
else if (i<10000)
firstdigit = i/1000;
else if (i<100000)
firstdigit = i/10000;
else (etc... all the way up to 1000000000)
Я знаю, что это не C#, но это удивляет любопытный, что в Python "добираются, первый символ строкового представления числа" быстрее!
Править: нет, я сделал ошибку, я забыл создавать снова интервал, извините. Развернутая версия это является самым быстрым.
$ cat first_digit.py
def loop(n):
while n >= 10:
n /= 10
return n
def unrolled(n):
while n >= 100000000: # yea... unlimited size int supported :)
n /= 100000000
if n >= 10000:
n /= 10000
if n >= 100:
n /= 100
if n >= 10:
n /= 10
return n
def string(n):
return int(str(n)[0])
$ python -mtimeit -s 'from first_digit import loop as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 275 msec per loop
$ python -mtimeit -s 'from first_digit import unrolled as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 149 msec per loop
$ python -mtimeit -s 'from first_digit import string as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 284 msec per loop
$
Очевидный, но медленный, математический подход:
int firstDigit = (int)(i / Math.Pow(10, (int)Math.Log10(i))));
int temp = i;
while (temp >= 10)
{
temp /= 10;
}
Результат в temp
int myNumber = 8383;
char firstDigit = myNumber.ToString()[0];
// char = '8'
Если Вы думаете, что ответ Keltex ужасен, попробуйте этого, это ДЕЙСТВИТЕЛЬНО ужасно, и еще быстрее. Это делает развернутый двоичный поиск для определения длины.
... leading code along the same lines
/* i<10000 */
if (i >= 100){
if (i >= 1000){
return i/1000;
}
else /* i<1000 */{
return i/100;
}
}
else /* i<100*/ {
if (i >= 10){
return i/10;
}
else /* i<10 */{
return i;
}
}
P.S. MartinStettner имел ту же идею.
вариация на ответ Anton:
// cut down the number of divisions (assuming i is positive & 32 bits)
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;
Имел ту же идею как Lennaert
int start = number == 0 ? 0 : number / (int) Math.Pow(10,Math.Floor(Math.Log10(Math.Abs(number))));
Это также работает с отрицательными числами.
Лучшее, которое я могу придумать:
int numberOfDigits = Convert.ToInt32(Math.Floor( Math.Log10( value ) ) );
int firstDigit = value / Math.Pow( 10, numberOfDigits );
...
Не очень симпатичный :)
[Отредактированный: первый ответ был действительно плох :)]
[Редактирование 2: Я, вероятно, советовал бы строковым решениям для управления, хотя]
[Редактирование 3: форматирование кода хорошо :)]
Попробуйте это
public int GetFirstDigit(int number) {
if ( number < 10 ) {
return number;
}
return GetFirstDigit ( (number - (number % 10)) / 10);
}
Править
Несколько человек запросили версию цикла
public static int GetFirstDigitLoop(int number)
{
while (number >= 10)
{
number = (number - (number % 10)) / 10;
}
return number;
}
Во-первых, необходимо выбрать то, что Вы подразумеваете под "лучшим" решением, конечно, который принимает во внимание эффективность алгоритма, его удобочитаемости/пригодности для обслуживания и вероятности ошибок, накапливающихся в будущем. Осторожные модульные тесты могут обычно избегать тех проблем, как бы то ни было.
Я выполнил каждый из этих примеров 10 миллионов раз, и значение результатов является количеством ElapsedTicks
это передало.
Без дальнейшей суматохи, от самого медленного до самого быстрого, алгоритмы:
int firstDigit = (int)(Value.ToString()[0]) - 48;
Результаты:
12,552,893 ticks
int firstDigit = (int)(Value / Math.Pow(10, (int)Math.Floor(Math.Log10(Value))));
Результаты:
9,165,089 ticks
while (number >= 10)
number /= 10;
Результаты:
6,001,570 ticks
int firstdigit;
if (Value < 10)
firstdigit = Value;
else if (Value < 100)
firstdigit = Value / 10;
else if (Value < 1000)
firstdigit = Value / 100;
else if (Value < 10000)
firstdigit = Value / 1000;
else if (Value < 100000)
firstdigit = Value / 10000;
else if (Value < 1000000)
firstdigit = Value / 100000;
else if (Value < 10000000)
firstdigit = Value / 1000000;
else if (Value < 100000000)
firstdigit = Value / 10000000;
else if (Value < 1000000000)
firstdigit = Value / 100000000;
else
firstdigit = Value / 1000000000;
Результаты:
1,421,659 ticks
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;
Результаты:
1,399,788 ticks
Примечание:
каждый проверочные вызовы Random.Next()
получить следующее int
Провел несколько тестов с одним из моих коллег здесь и обнаружил, что большинство решений не работают для чисел ниже 0.
public int GetFirstDigit(int number)
{
number = Math.Abs(number); <- makes sure you really get the digit!
if (number < 10)
{
return number;
}
return GetFirstDigit((number - (number % 10)) / 10);
}
Очень простой способ получить последнюю цифру:
int myInt = 1821;
int lastDigit = myInt - ((myInt/10)*10); // 1821 - 1820 = 1
int i = 4567789;
int digit1 = int.Parse(i.ToString()[0].ToString());