2017-12-25 15 views
0

Ich habe zwei Tabellen:MySQL - JOIN GROUP BY mit ORDER der Gruppierung

CREATE TABLE Person { 
    ID INT PRIMARY KEY, 
    Name VARCHAR(50) NOT NULL, 
    Surname VARCHAR(50) NOT NULL 
} 

und

CREATE TABLE Address { 
    ID INT PRIMARY KEY, 
    ID_Person INT NOT NULL, 
    Street VARCHAR(50), 
    HouseNumber VARCHAR(15), 
    City VARCHAR(75), 
    Zipcode VARCHAR(10), 
    CountryCode CHAR(2), 
    IsPrimary TINYINT(1) DEFAULT 0 
} 

Jede Person kann muptiple Adressen haben, aber höchstens kann man primär (IsPrimary = 1) .

Ich möchte eine Liste von Personen mit einer Adresse bekommen. Wenn eine Person eine primäre Adresse hat, sollte sie angegeben werden, wenn nicht, spielt es keine Rolle, welche Adresse abgerufen wird.

Ich habe diese Anfrage:

SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode 
FROM 
    Person AS p   
LEFT JOIN (select * from Address ORDER BY IsPrimary DESC) AS a ON p.ID = a.ID_Person 
GROUP BY p.ID 

aber, dass die Ergebnisse nicht erzielen, die ich erwarte. Ich erwartete, dass die erste Zeile der verbundenen Tabelle bei der Ausführung von GROUP BY abgerufen wird, aber das ist nicht der Fall.

ähnliche Frage wurde gefragt, here aber die Lösung ist ziemlich schwierig in meiner Situation.

Antwort

1

ORDER BY in einer Sub-Abfrage in der Regel nur verlangsamt hinunter Sie abfragen. Sie müssen das Ergebnis bestellen statt:

SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode 
FROM 
    Person AS p   
LEFT JOIN Address AS a ON p.ID = a.ID_Person 
GROUP BY p.ID ORDER BY a.isPrimary 

Diese Abfrage hat ein zweites Problem: Es ist nicht kompatibel ANSI, so dass es funktioniert nur in MySQL, wenn MySQL nicht ANSI-konform läuft.

Angenommen: Sie haben 1 p.ID mit zwei Zeilen in der Tabelle Address. Es gibt keine GROUP Funktionen, die auf Address.City angewendet wurden. Woher weiß die Datenbank, welche City angezeigt werden soll? Es ist nicht so, also siehst du ein zufälliges. Um dies zu verhindern, wenden Sie Funktionen auf alle Spalten an, die nicht in der Gruppe enthalten sind (oder platzieren Sie die Spalten in der Gruppe nach).

+0

Das funktioniert, danke! – Zbynek

1

In MySQL 8.0 wird dies am besten als Ranking-Abfrage durchgeführt.

WITH PersonAddress AS (
    SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode, 
    ROW_NUMBER() OVER (PARTITION BY p.ID ORDER BY a.IsPrimary DESC) AS rn 
    FROM Person AS p 
    LEFT OUTER JOIN Address AS a ON p.ID = a.ID_Person 
) 
SELECT * FROM PersonAddress WHERE rn = 1; 

Vor MySQL 8.0 sind Fensterfunktionen nicht verfügbar. Die Problemumgehung besteht darin, Sitzungsvariablen zu verwenden:

SELECT 
    t.Name, 
    t.Surname, 
    t.Street, 
    t.Housenumber, 
    t.City, 
    t.Zipcode 
FROM (
    SELECT 
    p.Name, 
    p.Surname, 
    a.Street, 
    a.Housenumber, 
    a.City, 
    a.Zipcode, 
    IF(p.ID = @pid, @rn:[email protected]+1, @rn:=1) AS rn, 
    @pid := p.ID 
    FROM (SELECT @pid:=0, @rn:=1) AS _init 
    CROSS JOIN Person AS p 
    LEFT OUTER JOIN Address AS a ON p.ID = a.ID_Person 
    ORDER BY p.ID, a.IsPrimary DESC 
) AS t 
WHERE t.rn = 1;