SQL с СЧЕТАМИ и СУММАМИ с кросс-объединением GROUP BY - PullRequest
0 голосов
/ 09 апреля 2011

Нужен гуру SQL, это убивает мои нейроны. У меня есть структура БД (упрощенная), как это:

DESC documents;
    id          INT PK
    bill_id     INT FK
    dtype       INT -- 1=receipts, 0=invoices
    total       DECIMAL

DESC bills;
    id          INT PK
    waiter_id   INT FK

DESC waiters;
    id          INT PK
    name        VARCHAR
    surname     VARCHAR

Совершенно очевидно, но мне нужно подсчитать и суммировать итоги по всем квитанциям (documents.dtype = 1) и счетам (documents.dtype = 0), сгруппированным по официанту. Я сделал два ВЫБОРЫ:

SELECT
        B.waiter_id,
        WA.name, 
        WA.surname, 
        COUNT(D.id) AS Receipts, 
        SUM(D.total) AS TotReceipts
FROM    
    documents D
    JOIN bills B ON (B.id = D.bill_id)
    JOIN waiters WA ON (WA.id = B.waiter_id)
WHERE 
    D.dtype = 1          
GROUP BY 
    waiter_id;

Хорошо, я получаю:

1, 'Mario',   'Rossi',   6, 485.20
2, 'Luigino', 'Bianchi', 1, 456.00

сделал второй SELECT, просто изменив тип documents.d в 0:

SELECT
        B.waiter_id,
        WA.name, 
        WA.surname, 
        COUNT(D.id) AS Invoices, 
        SUM(D.total) AS TotInvoices
FROM    
    documents D
    JOIN bills B ON (B.id = D.bill_id)
    JOIN waiters WA ON (WA.id = B.waiter_id)
WHERE 
    D.dtype = 0 
GROUP BY 
    waiter_id;

А теперь я получаю:

1, 'Mario', 'Rossi', 1, 38.00

Теперь я могу объединить два SELECTS

SELECT
        B.waiter_id,
        WA.name, 
        WA.surname, 
        COUNT(D.id) AS Receipts, 
        SUM(D.total) AS TotReceipts
FROM    
    documents D
    JOIN bills B ON (B.id = D.bill_id)
    JOIN waiters WA ON (WA.id = B.waiter_id)
WHERE 
    D.dtype = 1      
GROUP BY 
    waiter_id
UNION SELECT
        B.waiter_id,
        WA.name, 
        WA.surname, 
        COUNT(D.id) AS Invoices, 
        SUM(D.total) AS TotInvoices
FROM    
    documents D
    JOIN bills B ON (B.id = D.bill_id)
    JOIN waiters WA ON (WA.id = B.waiter_id)
WHERE 
    D.dtype = 0 
GROUP BY 
    waiter_id;

И я получаю:

1, 'Mario',   'Rossi',   6, 485.20
2, 'Luigino', 'Bianchi', 1, 456.00
1, 'Mario',   'Rossi',   1, 38.00

ммм, правильно, но мне нужны строки, сгруппированные по перекрестному объединению официантов! То есть я хочу одну строку для официанта Марио:

wid wname       wsurname    receipts    totreceipts     invoices        totinvoices
1,  'Mario',    'Rossi',    6,          485.20          1               38.0
2,  'Luigino',  'Bianchi',  1,          456.00          0               0.0

Это было бы просто замечательно, но я бы также хотел, чтобы еще два столбца суммировали такие числа, как:

wid wname       wsurname    receipts    totreceipts     invoices        totinvoices     docs    totdocs
1,  'Mario',    'Rossi',    6,          485.20          1               38.0            7       523.20
2,  'Luigino',  'Bianchi',  1,          456.00          0               0.0             1       456.00

И это было бы супер-ультра-круто.

Ответы [ 2 ]

2 голосов
/ 09 апреля 2011

Вы можете переместить условие из предложения where в оператор case, например:

SELECT
        B.waiter_id,
        WA.name, 
        WA.surname, 
        SUM(case when d.dtype = 1 then 1 end) AS Receipts, 
        SUM(case when d.dtype = 1 then D.total end) AS TotReceipts,
        SUM(case when d.dtype = 0 then 1 end) AS Invoices, 
        SUM(case when d.dtype = 0 then D.total end) AS TotInvoices
FROM    
    documents D
    JOIN bills B ON (B.id = D.bill_id)
    JOIN waiters WA ON (WA.id = B.waiter_id)
GROUP BY 
    waiter_id
0 голосов
/ 09 апреля 2011

Этот запрос возвращает то, что вы спросили

 SELECT
    B.waiter_id,
    WA.name, 
    WA.surname,
    (select count(id)             from documents where dtype = 0 and bill_id = B.id) AS Invoices, 
    (select isnull(sum(total), 0) from documents where dtype = 0 and bill_id = B.id) AS TotInvoices, 
    (select count(id)             from documents where dtype = 1 and bill_id = B.id) AS Receipts, 
    (select isnull(sum(total), 0) from documents where dtype = 1 and bill_id = B.id) AS TotReceipts
  FROM bills B
 inner join waiters WA on WA.id = B.waiter_id

Чтобы суммировать все итоги, вы можете сделать внутренний выбор для суммирования итогов как:

select  data.*, 
        data.Invoices + data.Receipts as docs,
        data.TotInvoices + data.TotReceipts as totaldocs
  from (
  select 
    B.waiter_id,
    WA.name, 
    WA.surname,
    (select count(id)             from documents where dtype = 0 and bill_id = B.id) AS Invoices, 
    (select isnull(sum(total), 0) from documents where dtype = 0 and bill_id = B.id) AS TotInvoices, 
    (select count(id)             from documents where dtype = 1 and bill_id = B.id) AS Receipts, 
    (select isnull(sum(total), 0) from documents where dtype = 1 and bill_id = B.id) AS TotReceipts
  from bills B
 inner join waiters WA on WA.id = B.waiter_id
 ) data
...