2015-06-15 3 views
1

Внутри больший запрос, я должен COUNT переменным, то если оно больше, чем 1, имею на счетном в виде строки в противном случае пустой строки:Избегайте вызов COUNT дважды в выражении CASE, (PostgreSQL)

CASE COUNT(measurement.id) > 1 THEN to_char(COUNT(measurement.id),' 999') ELSE '' 

Я боюсь, что это медленно, потому что я использую COUNT() дважды. Есть ли способ лучше?

+1

Счет будет оцениваться только один раз. –

+0

Было бы здорово, это где-то в документах? – RemcoGerlich

+1

@RemcoGerlich. , , Это очень сильно подразумевается в определении волатильности (http://www.postgresql.org/docs/9.4/static/xfunc-volatility.html). Я предполагаю, что это относится к функциям агрегации и что 'COUNT()' должным образом объявляется стабильным. –

ответ

3

Это выражение:

CASE COUNT(measurement.id) > 1 THEN to_char(COUNT(measurement.id),' 999') ELSE '' 

не медленно, потому что COUNT() вызывается дважды. Трудная работа по агрегированию данных - это та часть, в которой ключевые значения объединены. Отдельные функции агрегации обычно не особенно дороги (есть исключения, такие как COUNT(DISTINCT)). Таким образом, даже если бы это вызывалось несколько раз, это не было проблемой.

Вы можете изменить запрос на что-то более загадочное, как:

coalesce(to_char(nullif(count(measurement.id), 0), '999')), '') 

Это происходит подсчет 0, преобразует его в NULL, который затем превращается в пустую строку (и я думаю это было только оценивайте аргумент один раз в Postgres, хотя SQL Server будет оценивать его дважды, и в этом случае вы используете isnull() вместо coalesce()). Я предпочитаю вашу версию, если вы чувствуете необходимость конвертировать красивые числа в строки.

РЕДАКТИРОВАТЬ:

COUNT(), как представляется, определяется как «неизменны», который является еще более сильным, чем «стабильный». Я даже не уверен, что это правильно, но это так на SQL Fiddle. В любом случае, он, вероятно, не вызывается дважды, но дорогая часть - это GROUP BY.

+0

(Извините за небольшое эссе, я немного увлекся ...) Агрегаты действительно не имеют объявленного класса устойчивости. Запись в 'pg_proc' является просто заполнителем, чтобы зарезервировать подпись функции и предотвратить вызов в неагрегатном контексте (обратите внимание, что' prosrc' является просто ['aggregate_dummy'] (https://github.com/postgres /postgres/blob/aa9eac45ea868e6ddabc4eb076d18be10ce84c6a/src/backend/executor/nodeAgg.c#L2888), поэтому 'IMMUTABLE', вероятно, подходит). –

+0

Вся концепция классов устойчивости не может (легко) применяться здесь, поскольку кажущееся поведение (функция, сопоставляющая множество со скалярным значением) сильно отличается от реальности (последовательность значений, управляющая серией состояний переходов) , Большинство функций перехода являются технически «VOLATILE», несмотря на их заявления, поскольку они выполняют обновления на месте на аккумуляторе. Функция функции 'COUNT()' не относится к классификации, поскольку она фактически изменяет ее вход ... –

+0

Все это в сторону, агрегаты ведут себя так, как если бы они были «STABLE» (даже если это не так): [SQLFiddle] (http : //www.sqlfiddle.com/#! 15/70ef4/1) –

Смежные вопросы