2013-02-24 4 views
5

ich die folgende Abfrage bin mit der Gruppe Arbeitszeit und Kosten für Kunden aus drei Tabellen, einem für Kunden, ein für Arbeitszeiten und einem für Ausgaben:Mit GROUP BY und ORDER BY auf einer inneren SQL-Abfrage 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 

Sie können die Abfrage in einer Geige here arbeiten sehen.

Ich versuche diese Abfrage zu ändern, so dass für jeden Monat eine Zeile für jeden Monat nach Monat und dann Client sortiert ist. Ich versuche, so mit der folgenden geändertenen Abfrage zu tun:

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 

Sie können die geänderte Abfrage in Aktion here sehen.

Es funktioniert jedoch nicht ganz richtig. Für Client B wird nur eine Zeile zurückgegeben, obwohl eine Arbeitszeit im Januar 2013 und eine Ausgabe im Februar 2013 (also zwei Zeilen) vorhanden sind. Es scheint, dass die Zeilen von Client im Gegensatz zu Monat sortiert werden. Könnte jemand vorschlagen, wie die Abfrage zu ändern, würde die gewünschte Ausgabe, die für das Beispiel auf der zweite Geige zu bekommen sein:

╔════════╦═══════════╦═══════════╦══════════════╦══════════════╗ 
║ 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

Sie können als 'ORDER BY' für die beiden Unter wählt müssen. Legen Sie das für die endgültige Antwort. –

+1

Wenn Datum ein Datetime-Datentyp ist, warum/wie machen Sie einen Teilstring() darauf? – wildplasser

+0

Ihre Tabellen haben redundante Daten, Menge und Datum. Sie müssen Ihre Struktur weiter normalisieren und die Redundanz beseitigen. Die Abfrage ist zu zweideutig, Sie möchten bestimmte Daten sehen, aber es gibt keine Auswahlkriterien außer "Client-ID ist nicht null" **. Wenn Sie Daten für einen bestimmten Zeitraum nach Monat gruppiert anzeigen möchten, suchen Sie nach dem Datum. Ich würde zurücktreten und die Normalisierung als mein erstes Problem betrachten. –

Antwort

2

Sofern ich etwas in den Anforderungen nicht vermisse, was Sie tun müssen, ist eine Liste der Clients und der Daten zu bekommen und dann diese zu Ihren Unterabfragen beizutreten. So Ihre Frage wird sein:

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 

SQL Fiddle with Demo See.

Das Ergebnis ist:

| 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

Nein, Sie verpassen nichts.Ihre Abfrage gibt genau das zurück, was ich möchte. Danke vielmals! – Nick

+0

@Nick glücklich zu helfen, habe ich nur eine kleine Bearbeitung der ursprünglichen Abfrage, aber es gibt immer noch das gleiche Ergebnis. :) – Taryn

+0

Das Ergebnis Ihrer Bearbeitung scheint nicht ganz dasselbe zu sein. Es ist nicht nach Monat sortiert – Nick

0

Wenn Sie mit dem in einer Unterabfrage einen Auftrag zu tun, es spielt keine Rolle, denn Die äußere Abfrage kann (und muss möglicherweise) die Ergebnisse neu ordnen. Sie möchten der äußeren Abfrage eine Reihenfolge hinzufügen.

Ihr Problem ist, dass Sie versuchen, nach dem Monat und Client der B-Tabelle zu bestellen, und auch nach dem Monat und dem Client der C-Tabelle zu bestellen. Sie müssen die Reihenfolge von B.month, B.client und C.month definieren und für die äußere Abfrage in eine Reihenfolge bringen.

BTW, wenn Sie nur nach Monat in der Unterabfrage für die C-Tabelle gruppieren, dann Client ist nicht sinnvoll. Bei einigen Datenbanken, wie z. B. DB2, ist es nicht möglich, ein nicht aggregiertes Feld in eine Auswahl einzufügen, wenn es nicht in der Gruppe "Bis" enthalten ist.

+0

Danke, sowohl die Zeilen work_times als auch expens sind in der Geige nach 'Month, Client' gruppiert. Ich habe die Abfrage in meiner Frage geändert, um dies zu berücksichtigen. Ich bin mir nicht sicher, ob ich das gewünschte Ergebnis erhalten kann, indem ich nur eine ORDER BY zur äußeren Abfrage hinzufüge. Ich habe ein paar Kombinationen ausprobiert und es funktioniert nicht. Ein Teil des Problems besteht darin, dass die Kosten und die Arbeitszeit für Client B in derselben Zeile kombiniert werden, obwohl sie sich in einem anderen Monat befinden. – Nick