2012-04-24 2 views
6

Ich habe eine ungewöhnliche SQL-Tabelle (nicht meins), die die folgenden Felder (unter anderem) hat: last_name, primary_name, secondary_name, bezeichnend für Ehepaare. Der Nachname wird als geteilt angenommen (nicht sehr modern, ich weiß), und wenn es kein Paar ist, dann kann entweder primary_name oder secondary_name NULL sein. (Die Tabelle enthält auch mehrere Duplikate.)Kann ich eine SQL-Abfrage zwei Übereinstimmungen in jeder Zeile machen lassen?

Ich möchte eine Liste aller Namen ("first last") in der Datenbank erhalten, alphabetisiert in der üblichen Weise. Im Moment bin ich dabei zwei Durchgänge durch die Datenbank mit PHP und PDO:

$qstr = "SELECT DISTINCT primary_name, last_name 
      FROM members 
      WHERE primary_name IS NOT null 
      ORDER BY last_name, primary_name"; 
$sth = $dbh->prepare($qstr); 
$sth->execute(); 
// output the results 

$qstr = "SELECT DISTINCT secondary_name, last_name 
      FROM members 
      WHERE secondary_name IS NOT null 
      ORDER BY last_name, secondary_name"; 
$sth = $dbh->prepare($qstr); 
$sth->execute(); 
// output the new results 

Aber das Endergebnis nicht alphabetisiert, weil der zweite Durchgang beginnt wieder vorbei.

Wie kann ich alle Namen auf einmal vollständig alphabetisch sortiert bekommen? Gibt es eine Möglichkeit, dies in SQL zu tun, oder muss ich zwei Arrays erstellen und sie anschließend in PHP neu alphabetisch sortieren?

EDIT Die Datenbank sieht wie folgt aus:

last_name primary_name secondary_name 
---------------------------------------- 
Abrams  Joe   Susan 
Miller  Sam   Abby 

Die gewünschte Ausgabe etwas so sein würde:

["Joe Abrams","Susan Abrams","Abby Miller","Sam Miller"] 

Stattdessen, wenn der erste Durchgang alle Männer bekommt und die zweiten Durchlauf alle Frauen, bekomme ich etwas wie folgt:

["Joe Abrams","Sam Miller","Susan Abrams","Abby Miller"] 
+0

Können Sie ein Beispiel für eine Ausgabe veröffentlichen, die Sie sehen möchten (unter Verwendung von 4 oder 5 verschiedenen Fällen von Namenskombinationen)? –

Antwort

2

Eine Alternative ist UNION zu verwenden ...

SELECT 
    * 
FROM 
(
    SELECT primary_name AS pri_sec_name, last_name 
    FROM members 
    WHERE primary_name IS NOT null 

    UNION 

    SELECT secondary_name AS pri_sec_name, last_name 
    FROM members 
    WHERE secondary_name IS NOT null 
) 
    AS data 
ORDER BY 
    last_name, pri_sec_name 

HINWEIS:UNION(im Gegensatz zu) wird die Ergebnisse duplizieren.

Eine weitere Möglichkeit besteht darin, eine Verknüpfung in einer Mapping-Tabelle durchzuführen.

SELECT 
    members.last_name, 
    CASE WHEN map.mode = 1 THEN members.primary_name ELSE members.secondary_name END AS pri_sec_name 
FROM 
    members 
INNER JOIN 
    (SELECT 1 as mode UNION ALL SELECT 2 as mode) AS map 
    ON (map.mode = 1 AND members.primary_name IS NOT NULL) 
    OR (map.mode = 2 AND members.secondary_name IS NOT NULL) 
ORDER BY 
    1, 
    2 
+0

UNION ist eines der Dinge, die ich vor langer Zeit wegen mangelnder Nutzung vergessen hatte. Dies scheint zu funktionieren, aber können Sie mir den 'AS-Daten'-Teil der Anfrage erklären? – Blazemonger

+0

Macht nichts, der Fehler von SQL hat es nur für mich erklärt. – Blazemonger

+0

@Blazemonger - Es ist nur, um alles in eine Unterabfrage zu verpacken und dieser Unterabfrage einen Namen zu geben. Dies wird häufig als * Inline-Ansicht * bezeichnet, da Sie Ihre Unterabfrage als Ansicht behandeln. 'SELECT * FROM () AS MyViewName' – MatBailie

7

Wenn ich richtig verstehe, ich glaube, Sie für so etwas suchen:

select distinct coalesce(primary_name, secondary_name) as pri_sec_name, 
    last_name 
from members 
where coalesce(primary_name, secondary_name) is not null 
order by last_name, 
    coalesce(primary_name, secondary_name) 

aktualisieren

Es klingt wie in einigen Fällen Sie eine Zeile für eine last_name haben, wo beide PRIMARY_NAME und secondary_name ist ausgefüllt. Die Abfrage unten sollten Sie die Ausgabe, die Sie (sorry, keine COALESCE diesmal) wollen:

select last_name, pri_sec_name 
from (
    select primary_name as pri_sec_name, last_name from members where primary_name is not null 
    union all 
    select secondary_name as pri_sec_name, last_name from members where secondary_name is not null 
) a 
order by last_name, pri_sec_name 
+1

+1 für die Entschlüsselung. –

+0

+1 Ich liebe Coalesce! –

+0

Das erste Mal habe ich von 'coalesce' gehört. Was wird die Ausgabe dieses SQL sein? Es sieht für mich so aus, als würde ich immer noch eine Ergebniszeile für jede einzelne Tabellenzeile bekommen, wenn (meistens) ich zwei Ergebniszeilen für jede Tabellenzeile benötige. – Blazemonger

2

Ich glaube, Sie brauchen:

SELECT primary_name AS name 
    , last_name 
    FROM members 
    WHERE primary_name IS NOT NULL 
UNION 
SELECT secondary_name 
    , last_name 
    FROM members 
    WHERE secondary_name IS NOT NULL 
ORDER BY last_name, name 

Ein weiteres Umschreiben verwendet UNION ALL:

SELECT COALESCE(primary_name, secondary_name) AS name 
    , last_name 
    FROM members 
UNION ALL 
SELECT secondary_name 
    , last_name 
    FROM members 
    WHERE primary_name IS NOT NULL 
    AND secondary_name IS NOT NULL 
ORDER BY last_name, name 

Die zweite Version schneller sein können, aber es kann doppelte Ergebnisse zeigen.Wenn mehr Beispiel haben Sie diese Zeilen, eine Joe Jackson verheiratet mit Susan und ein verheiratet mit Lea:

last_name primary_name secondary_name 
---------------------------------------- 
Jackson Joe   Susan 
Jackson Joe   Lea 

Die erste Abfrage qould zeigen:

name last_name 
----------------- 
Joe Jackson 
Lea Jackson 
Susan Jackson 

während die zweite würde „Duplikate“ haben:

name last_name 
----------------- 
Joe Jackson 
Joe Jackson 
Lea Jackson 
Susan Jackson 

Welches ist mehr richtig, hängt von Ihren Spezifikt. Ab.

Verwandte Themen