2012-09-02 19 views
14

Próbuję wykonać zapytanie z postgresql. Baza zawiera dwie relacje: „Królestwo”, który zawiera kilka angielskich królów, i „dinasty”, który zawiera kilka osób z Dinasty stuartSQL: podzapytanie ma zbyt wiele kolumn

Relacja „królestwo” zawiera imię króla i gdy jego królestwo zaczęło i skończyło . Relacja "dinasty" obejmuje imię, płeć, narodziny i śmierć.

Próbuję zapytać, to król, który był najstarszy, gdy zmarł.

Z moim zapytaniu Otrzymuję ten błąd w wierszu 3 (nie w): subquery has too many columns

Jest to zapytanie:

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king, R1.birth, R1.death 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 

Co jest w środku NOT IN jest prawidłowe.

+1

Nie ma to wpływu na twój kod, ale proszę poprawnie przeliterować dynastię. –

Odpowiedz

18

Jesteś wystające trzy kolumny w swojej podzapytania, ale porównując jeden jeden z nich w klauzuli IN. Wystarczy wybrać odpowiednią kolumnę (r1.king) dla IN w podzapytaniu:

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 
+0

dziękuję :) – Epi

+0

Ponadto, jeśli można to zrobić, spróbuj przenieść podzapytania w klauzuli FROM (w postaci tabeli pochodzącej z odpowiednim polu dołączyć dalej), ponieważ będzie to znacznie szybciej, oceniając tylko raz, zamiast raz w rzędzie. – d11wtq

8

Jak odpowiedział, licznik kolumna nie pasuje, ale jest o wiele prostszy sposób to napisać.

Pisząc zapytania, najlepiej przemyśleć je etapami. Po pierwsze, trzeba wiedzieć, jak stary każdy król, kiedy zmarł:

SELECT *, death-birth AS lived_for FROM dinasty 

Teraz, gdy już, że można używać DISTINCT ON znaleźć najdłużej żył król dla każdego królestwa

SELECT DISTINCT ON(name) name, birth, death, lived_for 
    FROM (
     SELECT *, death-birth AS lived_for FROM dinasty 
    ) a 
    ORDER BY name, lived_for DESC 
; 

Różnica polega na tym, że pierwszy wiersz zostanie przypisany do każdej odrębnej wartości, dlatego ważne jest sparowanie go z poprawnym ORDER BY. Najpierw zamówiliśmy nazwę dinasty, a potem jak długo żył król dla w malejącej kolejności. Oznacza to, że pierwszy król pokazany dla każdej Dinasty będzie najdłużej mieszkał jeden, i to jest zapis, że DISTINCT ON zachowa dla każdego Dinasty.

Zauważ, że ja również usunięte JOIN kindgom, ale można dodać, że z powrotem w razie potrzeby:

SELECT k.*, oldest.* 
    FROM (
    SELECT DISTINCT ON(name) name, birth, death, lived_for 
     FROM (
      SELECT *, death-birth AS lived_for FROM dinasty 
     ) a 
     ORDER BY name, lived_for DESC 
    ) oldest 
    JOIN kingdom k ON k.king = oldest.name 
; 

Wreszcie, jeśli kiedykolwiek potrzebne do korzystania z wielu kolumn w sub-select, można użyć Konstrukcja ROW():

SELECT ... 
    FROM table_a 
    WHERE ROW(f1, f2, f3) NOT IN (SELECT f1a, f2a, f3a FROM ...) 
; 
+0

Dlaczego zostało to odrzucone? –

+0

Dobre pytanie; nic oczywiście nie jest dla mnie złe - pozostawienie komentarza w wyjaśnieniu byłoby uprzejme. –

+0

dziękuję za wskazanie opcji ROW! Rozwiązałem mój (nieco inny) problem :) – wmebane

Powiązane problemy