2013-02-24 17 views
5

Sto usando la seguente query per tempi di lavoro di gruppo e le spese per i clienti da tre tabelle, una per i clienti, uno per tempi di lavoro e uno per le spese:Utilizzando GROUP BY e ORDER BY in una query SQL INNER JOIN

SELECT a.*, 
     COALESCE(b.totalCount, 0) AS CountWork, 
     COALESCE(b.totalAmount, 0) AS WorkTotal, 
     COALESCE(c.totalCount, 0) AS CountExpense, 
     COALESCE(c.totalAmount, 0) AS ExpenseTotal 
FROM clients A 
     LEFT JOIN 
     (
      SELECT Client, 
        COUNT(*) totalCount, 
        SUM(Amount) totalAmount 
      FROM work_times 
      WHERE DATE BETWEEN '2013-01-01' AND '2013-02-01' 
      GROUP BY Client 
     ) b ON a.Client = b.Client 
     LEFT JOIN 
     (
      SELECT Client, 
        COUNT(*) totalCount, 
        SUM(Amount) totalAmount 
      FROM expenses 
      WHERE DATE BETWEEN '2013-01-01' AND '2013-02-01' 
      GROUP BY Client 
     ) c ON a.Client = c.Client 
WHERE b.Client IS NOT NULL OR 
     c.Client IS NOT NULL 

È possibile visualizzare la query di lavoro su un violino here.

Sto tentando di modificare questa query in modo che sia presente una riga per ciascun client per ogni mese ordinato per mese e quindi client. Sto cercando di farlo con la seguente query modificata:

SELECT a.*, 
     COALESCE(b.totalCount, 0) AS CountWork, 
     COALESCE(b.totalAmount, 0) AS WorkTotal, 
     COALESCE(c.totalCount, 0) AS CountExpense, 
     COALESCE(c.totalAmount, 0) AS ExpenseTotal 
FROM clients A 
     LEFT JOIN 
     (
      SELECT Client, 
        COUNT(*) totalCount, 
        SUM(Amount) totalAmount, 
        SUBSTR(Date, 1, 7) as Month 
      FROM work_times 
      GROUP BY Month,Client 
      ORDER BY Month 
     ) b ON a.Client = b.Client 
     LEFT JOIN 
     (
      SELECT Client, 
        COUNT(*) totalCount, 
        SUM(Amount) totalAmount, 
        SUBSTR(Date, 1, 7) as Month 
      FROM expenses 
      GROUP BY Month,Client 
      ORDER BY Month,Client 
     ) c ON a.Client = c.Client 
WHERE b.Client IS NOT NULL OR 
     c.Client IS NOT NULL 

Si può vedere la query modificata in azione here.

Non funziona comunque bene. Viene restituita una sola riga per il cliente B anche se a gennaio 2013 è previsto un orario di lavoro e una spesa a febbraio 2013 (quindi dovrebbero esserci 2 righe) e sembra che le righe siano ordinate dal cliente anziché dal mese. Qualcuno potrebbe suggerire come modificare la query per ottenere il risultato desiderato, che per l'esempio del secondo violino sarebbe:

╔════════╦═══════════╦═══════════╦══════════════╦══════════════╗ 
║ CLIENT ║ COUNTWORK ║ WORKTOTAL ║ COUNTEXPENSE ║ EXPENSETOTAL ║ 
╠════════╬═══════════╬═══════════╬══════════════╬══════════════╣ 
║ A  ║   1 ║  10 ║   1 ║   10 ║ 
║ B  ║   1 ║  20 ║   0 ║   0 ║ 
║ A  ║   1 ║  15 ║   0 ║   0 ║ 
║ B  ║   0 ║  0 ║   1 ║   10 ║ 
║ C  ║   1 ║  10 ║   0 ║   0 ║ 
╚════════╩═══════════╩═══════════╩══════════════╩══════════════╝ 
+0

Non è necessario il 'ORDINE BY' per i due sub-select. Mettilo per la risposta finale. –

+1

Se la data è un tipo di dati datetime, perché/come si fa una sottostringa() su di esso? – wildplasser

+0

Le tabelle contengono dati ridondanti, importo e data. È necessario normalizzare ulteriormente la struttura e sbarazzarsi della ridondanza. La query è troppo ambigua, desideri visualizzare dati specifici ma non ci sono criteri in nessuna selezione diversa da ** l'id del client non è nullo **. Se si desidera visualizzare i dati per un intervallo di date specificato, raggruppati per mese, quindi eseguire una ricerca per la data. Vorrei fare un passo indietro e guardare alla normalizzazione come il mio primo problema. –

risposta

2

A meno che non manchi qualcosa nei requisiti, ciò che è necessario è ottenere un elenco dei client e delle date e quindi aggiungerlo alle subquery. Quindi la query sarà:

SELECT a.*, 
    COALESCE(b.totalCount, 0) AS CountWork, 
    COALESCE(b.totalAmount, 0) AS WorkTotal, 
    COALESCE(c.totalCount, 0) AS CountExpense, 
    COALESCE(c.totalAmount, 0) AS ExpenseTotal 
FROM 
(
    select distinct c.Client, d.Month 
    from clients c 
    cross join 
    (
    select SUBSTR(Date, 1, 7) as Month 
    from work_times 
    union 
    select SUBSTR(Date, 1, 7) as Month 
    from expenses 
) d 
) A 
LEFT JOIN 
(
    SELECT Client, 
    COUNT(*) totalCount, 
    SUM(Amount) totalAmount, 
    SUBSTR(Date, 1, 7) as Month 
    FROM work_times 
    GROUP BY Month,Client 
    ORDER BY Month,Client 
) b 
    ON a.Client = b.Client 
    and a.month = b.month 
LEFT JOIN 
(
    SELECT Client, 
    COUNT(*) totalCount, 
    SUM(Amount) totalAmount, 
    SUBSTR(Date, 1, 7) as Month 
    FROM expenses 
    GROUP BY Month,Client 
    ORDER BY Month,Client 
) c 
    ON a.Client = c.Client 
    and a.month = c.month 
WHERE b.Client IS NOT NULL OR 
     c.Client IS NOT NULL 
order by a.month, a.client 

Vedi SQL Fiddle with Demo.

Il risultato è:

| CLIENT | MONTH | COUNTWORK | WORKTOTAL | COUNTEXPENSE | EXPENSETOTAL | 
-------------------------------------------------------------------------- 
|  A | 2013-01 |   1 |  10 |   1 |   10 | 
|  B | 2013-01 |   1 |  20 |   0 |   0 | 
|  A | 2013-02 |   1 |  15 |   0 |   0 | 
|  B | 2013-02 |   0 |   0 |   1 |   20 | 
|  C | 2013-02 |   1 |  10 |   0 |   0 | 
+0

No, non ti manca nulla.La tua query restituisce esattamente ciò che voglio. Molte grazie! – Nick

+0

@Non felice di aiutarti, ho appena apportato una leggera modifica alla query originale, ma restituisce comunque lo stesso risultato. :) – Taryn

+0

Il risultato della tua modifica non sembra essere lo stesso. Non è ordinato per Mese – Nick

0

Se fate un ordine in una sotto-query, non importa, perché la query esterna potrebbe (e potrebbe essere necessario) riordinare i risultati. Vuoi aggiungere un ordine alla query esterna.

Il tuo problema è che stai tentando di ordinare dal mese e dal cliente della tabella B, e anche ordinare per mese e cliente della tabella C. È necessario definire l'ordine di B.month, B.client e C.month e inserirlo in un ordine per la query esterna.

BTW, se si raggruppa solo per mese nella sottoquery per la tabella C, il client non è significativo. Alcuni database, come DB2, non ti permettono di inserire un campo non aggregato in una selezione se non è nel gruppo per.

+0

Grazie, sia le righe work_times che le righe spese sono raggruppate per 'Month, Client' in the fiddle. Ho modificato la domanda nella mia domanda per riflettere questo. Non sono sicuro di poter ottenere il risultato che sto cercando semplicemente aggiungendo un ORDER BY alla query esterna. Ho provato alcune combinazioni e non funziona. Parte del problema è che la spesa e il tempo di lavoro per il cliente B vengono combinati nella stessa riga anche se si trovano in un mese diverso. – Nick