AVG и тип money

Изображение msi

Мне кажется странным, что я не могу написать следующее

SELECT avg(price) FROM PC,

а вынужден делать двойное преобразование типа, да еще и вычищать форматирование:

 SELECT avg(regexp_replace(price::text, '[$,]', '', 'g')::numeric) FROM pc;

Хотя с другой стороны, я могу написать так:

SELECT sum(price)/count(price) AS avg_foo FROM pc;

Что характерно, я получаю в последнем случае в качестве результата тип money, что и должно бы быть при использовании функции AVG, т.к. согласно стандарта, результат агрегата наследует тип данных аргумента.

Предполагаю, что тема избита, поэтому хотелось хотя бы получить ссылку на объяснение такого поведения.

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

Странно всё это. А вы можете

Странно всё это. А вы можете дать табличку для примера, чтобы я у себя попробовал?

Конечно

Изображение msi

CREATE TABLE PC (
	code int NOT NULL ,
	model varchar (50) NOT NULL ,
	speed smallint NOT NULL ,
	ram smallint NOT NULL ,
	hd real NOT NULL ,
	cd varchar (10) NOT NULL ,
	price money NULL 
);
INSERT INTO PC VALUES(1,'1232',500,64,5,'12x','600');
INSERT INTO PC VALUES(2,'1121',750,128,14,'40x','850');
INSERT INTO PC VALUES(3,'1233',500,64,5,'12x','600');
INSERT INTO PC VALUES(4,'1121',600,128,14,'40x','850');
INSERT INTO PC VALUES(5,'1121',600,128,8,'40x','850');
INSERT INTO PC VALUES(6,'1233',750,128,20,'50x','950');
INSERT INTO PC VALUES(7,'1232',500,32,10,'12x','400');
INSERT INTO PC VALUES(8,'1232',450,64,8,'24x','350');
INSERT INTO PC VALUES(9,'1232',450,32,10,'24x','350');
INSERT INTO PC VALUES(11,'1233',900,128,40,'40x','980');
INSERT INTO PC VALUES(12,'1233',800,128,20,'50x','970');

Можете также попробовать из консоли (используется та же база), правда, там пока ошибка не выводится.

Ага. Ну вот собственно я

Ага. Ну вот собственно я выполнил SELECT и увидел причину:

SELECT avg(price) FROM PC;
ERROR:  функция avg(money) не существует
СТРОКА 1:SELECT avg(price) FROM PC;
                ^
ПОДСКАЗКА:  No function matches the given name and argument types. You might need to add explicit type casts.

Т.е. для типа money не существует агрегатная функция avg, поэтому и не работает то, что вы хотите.
И нарушением стандарта это не является. Например avg также не будет существовать для типа DATE.

Теперь идём в мануал на страницу посвещённую агрегатным функциям:
http://postgresql.ru.net/manual/functions-aggregate.html
и видим, что данная функция работает только для типов: smallint, int, bigint, real, double precision, numeric, or interval

Собственно добавить тут больше нечего.

Это я прочитал

Изображение msi

: Т.е. для типа money не существует агрегатная функция avg, поэтому и не работает то, что вы хотите.

Читать я умею. :-)
Мне непонятно, почему это она не существует, если существует sum/count?

: И нарушением стандарта это не является. Например avg также не будет существовать для типа DATE.

Не думаю, что это так. Для DATE не существует sum/count, поскольку это лишено смысла, а средняя цена или стоимость имеет вполне определенный смысл.

Да, что касается стандарта, то там (SQL:2003) денежного типа нет вообще. Но я думаю, что если он появится, то AVG для него будет существовать, как для других числовых типов.

Мне непонятно, почему это она

Мне непонятно, почему это она не существует, если существует sum/count?
Потому что так решили разработчики. Вообще насколько я помню мануал, там написано, что тип money оставлен для совместимости, но настоятельно рекомендуется использовать вместо него numeric

Кстати судя по тому же мануалу, написать агрегатную функцию для этого типа не особенно сложно.

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

Back to top

(С) Виктор Вислобоков, 2008-2023