2012-06-29 4 views
4

У меня есть таблица продаж продуктов, которые могут выглядеть следующим образом:Эффективное использование SQL GROUP BY, SUM, COUNT

product | amount | ptype | pdate  
p1  | 1.00  | sale  | 01/01 
p1  | 2.00  | base  | 01/02 
p2  | 1.50  | sale  | 02/03 
p3  | 5.25  | base  | 10/10 

, и я хотел бы построить таблицу, которая показывает один продукт для каждой строки, сумма из сумм, если продукт уникален, покажите, что тип else показывает тип как «VAR», если продукт уникален, покажите дату еще, чтобы показать дату как NULL. Так что результат выглядит следующим образом:

product | total | ptype | pdate  
p1  | 3.00  | VAR  | (NULL) 
p2  | 1.50  | sale  | 02/03 
p3  | 5.25  | base  | 10/10 

Я достижение результата, мне нужно, выполнив следующие действия:

SELECT DISTINCT product 
,(SELECT SUM(amount) FROM T as b GROUP BY b.product HAVING a.product = b.product) as total 
,(SELECT CASE WHEN COUNT(*) = 1 THEN a.ptype ELSE 'VAR' END from T as b GROUP BY b.product HAVING a.product = b.product) as ptype 
,(SELECT CASE WHEN COUNT(*) = 1 THEN a.pdate ELSE NULL END from T as b GROUP BY b.product HAVING a.product = b.product) as pdate 
FROM T as a 

Но я хотел бы знать, если есть более эффективный способ, который позволяет выполнить такой же результат.

ответ

6

Нет необходимости использовать любую форму подзапроса или встроенного представления. В зависимости от сложности механизма базы данных эти конструкции могут негативно повлиять на производительность.

Вот что вы запросили, и он должен надежно дать результат с помощью одного сканирования таблицы даже на самом примитивном двигателе SQL.

select product, 
     sum(amount) as amount, 
     case when count(*)=1 then min(ptype) else 'VAR' end as ptype, 
     case when count(*)=1 then min(pdate) else null end as pdate 
    from T 
group by product 

Следующее не то, что вы просили, но я думаю, что это может быть ближе к тому, что вы на самом деле ищете. Он сообщает ptype как VAR или pdate как NULL, если есть несколько разных значений, составляющих совокупность.

Я добавил столбец pcount, чтобы вы все еще могли идентифицировать синглетные агрегаты, даже если оба типа ptype и pdate не являются nulll.

select product, 
     sum(amount) as amount, 
     count(*) as pcount, 
     case when count(distinct ptype)=1 then min(ptype) else 'VAR' end as ptype, 
     case when count(distinct pdate)=1 then min(pdate) else null end as pdate 
    from T 
group by product 
-1

Попробуйте этот бит кода:

SELECT DISTINCT product, x.total, 
IF(COUNT(x.ptype) > 1, 'VAR', x.ptype) AS ptype, 
IF(COUNT(x.pdate) > 1, NULL, x.pdate) AS pdate 
FROM (SELECT DISTINCT product, SUM(amount) AS total, ptype, pdate FROM table GROUP BY product) AS x 
JOIN table ON x.product = table.product 
GROUP BY x.product; 

Надеемся, что она работает.

+0

Этот SQL не будет работать на SQL Server; не уверены в других механизмах баз данных. –

+0

В Sybase это дает мне ошибку, говоря, что 'ptype' и 'pdate' также должны появляться в GROUP BY. –

+0

Ничего себе, я был пойман с моими штанами на этом. Полностью забыл, что для выполнения групповых функций вам необходимо группировать таблицу. – Palladium

1

Если вы используете это против любой крупной базы данных (например, SQL Server), оптимизатор запросов, скорее всего, заботиться о большей части оптимизации от вашего имени. Тем не менее, вы можете сделать это довольно легко с внутреннего запроса, который имеет одну группу. Вот пример, который работает и вы можете играть с:

http://sqlfiddle.com/#!3/f2e05/19/1

+0

Мой запрос выполняет почти то же самое, что и первый запрос, предлагаемый @dbenham; Я сделал то же замечание, что это может быть не то, что вы на самом деле хотите. Я отвечу на этот ответ. :) –