2009-07-17 17 views
2

Ich habe den folgenden 3 TabellenWerte aus mehreren Tabellen auf einer Reihe

Table1 

ID | NAME 
----------- 
1 | X 
2 | Y 
3 | Z 


Table2 

ID | NAME 
----------- 
1 | A 
2 | B 
3 | C 

Table3 
ID | P (Boolean field) | Other cols 
1 | True ... 
2 | True.... 
1 | False 

Jetzt brauche ich eine Abfrage auf table3, die Folgendes zu tun hat:

anzuzeigen das Namensfeld der Tabelle 1 und Tabelle 2 . Aber mein Problem ist, dass wenn Feld P auf table3 wahr ist, ich will es den Namen des Feldes von Tabelle2 anzeigen, wo table2.id = table3.id, aber wenn es falsch ist, ich brauche es den Namen von table1 Name Feld wo table1 zu lesen. id = table3.id.

Das Programm, das die Ergebnisse anzeigen wird, ist eine Desktop-Anwendung, und ich könnte es mit einer Prozedur oder etwas tun, um sie anzuzeigen, aber wäre schöner, wenn ich eine SQL-Abfrage für mich haben würde.

Antwort

3

Dies:

SELECT CASE WHEN p 
     THEN 
     (
     SELECT name 
     FROM table2 t2 
     WHERE t2.id = t3.id 
     ) 
     ELSE 
     (
     SELECT name 
     FROM table1 t1 
     WHERE t1.id = t3.id 
     ) 
     END 
FROM table3 t3 

oder dies:

SELECT CASE WHEN p THEN t2.name ELSE t1.name END 
FROM table3 t3 
JOIN table1 t1 
ON  t1.id = t3.id 
JOIN table1 t2 
ON  t2.id = t3.id 

In Systemen in der Lage HASH JOIN tun (dh Oracle, SQL Server, PostgreSQL, aber nicht MySQL), der zweite ist besser, wenn Die booleschen Werte sind gleichmäßig verteilt, d.h. e. es gibt viele TRUE 's und FALSE' s, und wenn ist ziemlich groß.

Die erste ist besser, wenn es eine Schrägstellung in der Verteilung ist, wenn es viel weniger Zeilen in table3 dann in table1 oder table2 ist, oder wenn Sie mit MySQL.

Update:

Wenn die Mehrheit der Felder falsch sind, wird die folgende Abfrage wahrscheinlich die beste sein:

SELECT CASE WHEN p THEN 
     (
     SELECT name 
     FROM table2 t2 
     WHERE t2.id = t3.id 
     ) 
     ELSE t1.name 
     END AS cname 
FROM table3 t3 
JOIN table1 t1 
ON  t1.id = t3.id 
ORDER BY 
     cname 

Subquery wird hier nur als Ausweichlösung verwendet werden, und wird ausgeführt nur für die seltenen TRUE Werte.

Update 2:

Ich kann es nicht auf Firebird überprüfen, aber auf den meisten Systemen die ORDER BY Syntax wie in Abfrage oben arbeiten. Wenn dies nicht der Fall, wickeln Sie die Abfrage in eine Inline-Ansicht:

SELECT cname 
FROM (
     SELECT CASE WHEN p THEN 
       (
       SELECT name 
       FROM table2 t2 
       WHERE t2.id = t3.id 
       ) 
       ELSE t1.name 
       END AS cname 
     FROM table3 t3 
     JOIN table1 t1 
     ON  t1.id = t3.id 
     ) q 
ORDER BY 
     cname 

, obwohl es die Leistung beeinträchtigen kann (zumindest in MySQL es tut).

+0

Die Mehrheit wird das Feld falsch ist, scheint so, dass die erste mir passen wird besser – zz1433

+0

Sie können dann mit 'table2' (die Namen die falschen Werte) und verwenden' table1' in einer Unterabfrage kommen als ein Rückfall. – Quassnoi

+0

danke, das hat wie ein Zauber funktioniert, aber es gibt ein letztes Ding, wo ich deine Hilfe gebrauchen könnte. Gibt es eine Möglichkeit, die Daten nach der Spalte "Name" in der Case-Anweisung zu sortieren? – zz1433

1

können Sie

select if(P, t1.name, t2.name) ... 
0
SELECT `id`, IF(`table3`.`P`, `table2`.`name`, `table1`.`name`) AS `name` 
FROM `table3` 
JOIN `table2` USING (`id`) 
JOIN `table1` USING (`id`) 
0

Möglicherweise nicht eine Option verwenden, aber manchmal wird ein Schema Redesign eine Menge Probleme lösen. Jede Lösung, die Funktionen pro Zeile ausführt, sollte sehr sorgfältig auf Leistungsprobleme untersucht werden (eigentlich alle Abfrage sollte kontinuierlich auf Leistungsprobleme überwacht werden, sondern vor allem per-Zeile Funktion).

Betrachten wir also den Tabellen 1 und 2 zusammen kombiniert: in der Regel nur erzieht seinen Kopf

select a.Id, b.Name, a.OtherCols 
from Table3 a, Table1And2 b 
where a.Id = b.Id and a.P = b.isTable2 

Die Performance-Problem:

Table1And2: 
    Id | IsTable2 | Name 
    ---+----------+----- 
    1 | false | X 
    2 | false | Y 
    3 | false | Z 
    1 | true  | A 
    2 | true  | B 
    3 | true  | C 
    Primary key (Id,IsTable2) 
    Possible index on (IsTable2) as well, depending on DBMS. 

Table3: 
    Id | P (Boolean field) | OtherCols 
    ---+--------------------+---------- 
    1 | true    | 
    2 | true    | 
    1 | false    | 

dann Ihre Abfrage wird ein relativ einfaches (und fast sicher blendend schnell) für große Tabellen, Mainframe-Größen, bei denen 5 Millionen Zeilen als Konfigurationstabelle betrachtet werden :-) Es ist vielleicht nicht notwendig für die Art von Tabellen, mit denen Sie es zu tun haben, aber es ist ein nützliches Werkzeug in der Waffenkammer.

+0

Das ist nicht möglich, da table2 Verweise auf Zeilen aus table1 (Fremdschlüssel, eine oder zwei Abfragen auf Tabelle1 für "comprired by" Zeilen) Sie haben auch eine andere Struktur in den anderen Spalten. – zz1433

+0

Nun, technisch kann man Fremdschlüssel haben, die auf die gleiche Tabelle verweisen und die verschiedenen Strukturen könnten auf noch mehr Tabellen getrennt werden :-) Aber irgendwann (und es ist wahrscheinlich zu diesem Zeitpunkt genau dort), werden Schemadesigns mehr Probleme als sie ' Re-Wert - Sie sollten wahrscheinlich für eine der per-Zeile-Funktion Antworten gehen und nur sicherstellen, dass ihre Leistung ist gut genug für Ihre Tischgröße (wahrscheinlich, wenn Sie Tabellen sind massiv). – paxdiablo

1

Es ist so einfach wie diese Abfrage in mysql.

 SELECT T3.ID, 
       T3.P, 
       IF(T3.P = true, T2.NAME, T1.NAME) AS NAME 
     FROM Table3 T3 
     LEFT JOIN Table2 T2 ON T2.ID = T3.ID 
     LEFT JOIN Table1 T1 ON T1.ID = T3.ID 
Verwandte Themen