2016-08-09 87 views
0

Ich habe eine PSQL-Abfrage, wo der AND-Parameter in der linken beitreten in einer anderen Tabelle Prüftabelle Beispiel unten.LINKS Verbinden Sie PSQL, wo der AND-Parameter in einer anderen Tabelle ist

Rechnungen

id | account |  invoice_date  | reference | total_amount | status 
-----+---------+-------------------------+-----------+--------------+-------- 
164 |  100 | 2016-08-03 03:05:08.996 |  161 |  2000.00 |  
165 |  100 | 2016-08-03 21:42:07.865 |  164 |   0 |  
167 |  100 | 2016-08-03 22:56:41.731 |  166 |  100.00 |  
168 |  100 | 1970-01-01 00:33:20  |  161 |   200 |  
169 |  100 | 2016-08-08 00:00:00  |  161 |   200 | 

Invoice_items

id | invoice | invoice_item_type | product | quantity | unit_price | reference | amount 
-----+---------+-------------------+---------+----------+------------+-----------+--------- 
143 |  164 |     1 |  6 |   |   |  161 | 2000.00 
144 |  165 |     1 |  11 |   |   |  164 |  0 
145 |  167 |     1 |  8 |   |   |  166 | 100.00 

Es gibt auch eine andere Tabelle PRODUCTS aber die einzige relevante Feld dort id

ist dies ist meine Abfrage

select products.id, sum(invoice_items.amount) as total_revenue 
from products 
    left join invoice_items on invoice_items.product = products.id 
    left join invoices on invoice_items.invoice = invoices.id 
         and invoices.invoice_date= current_date 
group by products.id; 

Die Abfrage, die ich ausführen soll, besteht darin, alle Produkt-IDs aufzulisten, und in der Spalte total_revenue die Summe der Verkäufe für das Produkt (add 'menu' in der Tabelle bill_items, wo das Feld 'product' ähnlich ist) für den aktuellen Tag (gefunden auf Rechnungen Tabelle). Aber wenn ich diese Abfrage ausführe, listet sie alle total_ounts für die Produkte auf. Was vermisse ich?

Probenausgang. 8, 6 und 11 müssen

id | total_revenue 
-----+--------------- 
125 |    
154 |    
119 |    
129 |    
    8 |  100.00 
112 |    
    5 |    
132 |    
104 |    
113 |    
143 |    
152 |    
121 |    
127 |    
165 |    
139 |    
146 |    
    15 |    
    2 |    
147 |    
149 |    
166 |    
169 |    
    13 |    
106 |    
122 |    
    9 |    
    11 |    0 
110 |    
120 |    
130 |    
155 |    
134 |    
136 |    
101 |    
168 |    
131 |    
157 |    
161 |    
103 |    
150 |    
159 |    
107 |    
108 |    
145 |    
    4 |    
    12 |    
158 |    
167 |    
138 |    
162 |    
100 |    
156 |    
163 |    
124 |    
123 |    
109 |    
153 |    
102 |    
105 |    
151 |    
116 |    
133 |    
140 |    
160 |    
148 |    
126 |    
141 |    
    7 |    
118 |    
    10 |    
164 |    
128 |    
    14 |    
144 |    
135 |    
    1 |    
    6 |  2000.00 
    3 |    
137 |    
117 |    
142 |    
111 |   
+1

Was meinst du mit _8, 6 und 11 muss leer sein. Da Sie 'und' für das Datum im' left join' haben, werden die Produkte hinzugefügt, die nicht übereinstimmen. Wenn Sie Ihre Anfrage betrachten, sollte sogar ein innerer Join ausreichen, wenn Sie nur die Einnahmen für Produkte wünschen, für die eine Rechnung vorliegt. – Neeraj

Antwort

0

Der Einschränkungstermin Filterung wird Datensätze in der Fakturentabelle aus, während Sie die Datensätze in der Tabelle invoice_items herausfiltern müssen - dies geschieht jedoch nicht, da beide Links sind. Eine abgeleitete Tabelle wird dies leicht lösen und das gewünschte Ergebnis liefern. Ich habe auch einige Tabellenalias für Prägnanz und Lesbarkeit hinzugefügt.

So:

SELECT 
    p.id, SUM(inv.amount) AS total_revenue 

FROM 
    products p LEFT JOIN 

    (SELECT 
     ii.product, i.invoice_date, ii.amount 
    FROM 
     invoice_items ii JOIN 
     invoices i ON 
      ii.invoice = i.id) inv ON 
      inv.product = p.id AND 
      inv.invoice_date= current_date 

GROUP BY p.id; 
+1

Dies hat den Trick gemacht, ändern Sie einfach das ii.invoice_date für die abgeleitete Tabelle zu i.invoice_date. Danke: * –

+0

Ups, ja, in der Tat - das habe ich jetzt korrigiert. –

0

Sie bekommen eine große Anzahl von NULL-Werte leer sein, die auf der Grundlage Ihrer Abfrage zu erwarten scheint.

Dies scheint wie ein "INNER" Join-Typ Problem statt einer "linken" Join. Linker Join behält alle Instanzen bei, in denen keine Rechnungen für ein Produkt in der Ergebnismenge vorhanden sind.

Sie können auch die gesamte Abfrage über „DATE“ in die having-Klausel bewegen (persönlich, ich ziehe Subqueries in WO /, wie ich die Logik klarer finden): nur

SELECT products.id, SUM(invoice_items.amount) AS total_revenue 
FROM products 
    INNER JOIN invoice_items ON invoice_items.product = products.id 
HAVING EXISTS (SELECT 1 FROM invoices WHERE invoice_items.invoice = invoices.id 
         AND invoices.invoice_date= current_date) 
GROUP BY products.id; 
0

ich sehe. Eine kleinere Beispieldaten mit gewünschten Ergebnissen wäre hilfreich.

Das Problem ist ein wenig kompliziert zu erklären. Die left join hält alle Produkte und Rechnungen, unabhängig vom Datum. Die letzte Verknüpfung zu invoices bringt Rechnungen, die nur am aktuellen Datum übereinstimmen. Da Sie jedoch in der zweiten Tabelle summieren, wird jede übereinstimmende Zeile einmal angezeigt (auch wenn keine Rechnungspositionen für den Tag vorhanden sind) und in Ihren Ergebnissen angezeigt.

Die Lösung: Verwenden Sie eine case Anweisung, um zu bestimmen, ob eine Übereinstimmung in der Tabelle invoice Artikel ist:

select p.id, 
     sum(ii.amount * (case when i.id is not null then 1 end)) as total_revenue 
from products p left join 
    invoice_items ii 
    on ii.product = p.id left join 
    invoices i 
    on ii.invoice = i.id and i.invoice_date = current_date 
group by p.id; 

Ich vermute auch, dass die richtige Voraussetzung für das Datum ist:

 on ii.invoice = i.id and i.invoice_date >= current_date and 
     i.invoice_date < current_date + interval '1 day' 

Wenn Sie dies als Unterabfrage speichern, wird auch die äußere Aggregation gespeichert, und das Problem sollte ebenfalls behoben werden:

+0

Ich würde erwarten, dass die Leistung des obigen Beispiels mit einer Unterabfrage in der Hauptauswahl sehr schlecht ist, sobald die Tabellen mehr als eine triviale Anzahl von Datensätzen erreichen. Eine abgeleitete Tabelle wird wahrscheinlich viel besser funktionieren, da sie nur einmal berechnet werden muss, nicht für jedes Produkt. –

+0

@SimonWoolf. . . Mit der richtigen Indexierung könnte die Unterabfrage der schnellste Ansatz sein. –

+0

Wie so? Die gleiche Indexierung verbessert auch die Leistung der abgeleiteten Tabelle, die meiner Erfahrung nach immer diese Vorgehensweise übertrifft. –