2009-07-01 14 views
0

Ein Freund bat mich um Hilfe bei der Erstellung einer Abfrage, die zeigen würde, wie viele Teile jedes Modells an jedem Tag des Monats verkauft wurden und Nullen zeigten, wenn keine Stücke für ein bestimmtes Modell verkauft wurden an einem bestimmten Tag, auch wenn an diesem Tag keine Artikel eines Modells verkauft werden. Ich habe die unten stehende Abfrage gefunden, aber es funktioniert nicht wie erwartet. Ich bekomme nur Aufzeichnungen für die Modelle, die verkauft wurden, und ich weiß nicht warum.Linke und rechte Verbindung in einer Abfrage

select days_of_months.`Date`, 
     m.NAME as "Model", 
     count(t.ID) as "Count" 
    from MODEL m 
    left join APPLIANCE_UNIT a on (m.ID = a.MODEL_FK and a.NUMBER_OF_UNITS > 0) 
    left join NEW_TICKET t on (a.NEW_TICKET_FK = t.ID and t.TYPE = 'SALES' 
and t.SALES_ORDER_FK is not null) 
right join (select date(concat(2009,'-',temp_months.id,'-',temp_days.id)) as "Date" 
       from temp_months 
       inner join temp_days on temp_days.id <= temp_months.last_day 
       where temp_months.id = 3 -- March 
      ) days_of_months on date(t.CREATION_DATE_TIME) = 
date(days_of_months.`Date`) 
group by days_of_months.`Date`, 
     m.ID, m.NAME 

Ich hatte die temporären Tabellen temp_months und temp_days geschaffen, um die Tage alle für jeden Monat zu erhalten. Ich benutze MySQL 5.1, aber ich versuche, die Abfrage ANSI-konform zu machen.

Antwort

6

Sie sollten Ihre Reisedaten und Modelle CROSS JOIN, so dass Sie genau ein Rekord-Paar für jeden Tag-Modell haben, egal was, und dann LEFT JOIN anderen Tabellen:

SELECT date, name, COUNT(t.id) 
FROM (
     SELECT ... 
     ) AS days_of_months 
CROSS JOIN 
     model m 
LEFT JOIN 
     APPLIANCE_UNIT a 
ON  a.MODEL_FK = m.id 
     AND a.NUMBER_OF_UNITS > 0 
LEFT JOIN 
     NEW_TICKET t 
ON  t.id = a.NEW_TICKET_FK 
     AND t.TYPE = 'SALES' 
     AND t.SALES_ORDER_FK IS NOT NULL 
     AND t.CREATION_DATE_TIME >= days_of_months.`Date` 
     AND t.CREATION_DATE_TIME < days_of_months.`Date` + INTERVAL 1 DAY 
GROUP BY 
     date, name 

Die Art und Weise Sie es jetzt tun bekommen Sie NULL ist in model_id für die Tage, die Sie keine Verkäufe haben, und sie sind zusammen gruppiert.

Notiere die JOIN Bedingung:

AND t.CREATION_DATE_TIME >= days_of_months.`Date` 
AND t.CREATION_DATE_TIME < days_of_months.`Date` + INTERVAL 1 DAY 

statt

DATE(t.CREATION_DATE_TIME) = DATE(days_of_months.`Date`) 

Diese Abfrage sargable (von Indizes optimiert) wird dazu beitragen

+0

Müssen Sie nicht specifico Uter Joins tun. Ich bin nicht zu vertraut mit mysql, aber in SQL-Server, wenn Sie innere/äußere weglassen es standardmäßig auf innere. –

+1

@dan s: LINKS und RECHTS bedeuten OUTER. – Quassnoi

+0

Das löste mein Problem. Danke vielmals! –

0

Sie müssen Outer-Joins verwenden, da sie Es ist nicht erforderlich, dass jeder Datensatz in den beiden verbundenen Tabellen einen übereinstimmenden Datensatz enthält.

http://dev.mysql.com/doc/refman/5.1/en/join.html

+0

Wenn Sie die Abfrage lesen, werden Sie feststellen, dass ich bereits linke und rechte äußere Joins verwende. –

0

Sie suchen nach einem OUTER suchen beizutreten. Ein linker äußerer Join erzeugt eine Ergebnismenge mit einem Datensatz von der linken Seite des Joins, auch wenn die rechte Seite keinen Datensatz enthält, mit dem ein Join aufgenommen werden soll. Ein rechter äußerer Join macht das gleiche in der entgegengesetzten Richtung, erzeugt einen Datensatz für den rechten Seitentabellen, selbst wenn die linke Seite keinen entsprechenden Datensatz aufweist. Jede Spalte, die aus der Tabelle projiziert wird, die keinen Datensatz enthält, wird im Join-Ergebnis einen NULL-Wert haben.

Verwandte Themen