2009-02-12 6 views
37

Ich bin ein Anfänger, wenn es um SQL-Syntax geht.Wie kombiniere ich 2 Select-Anweisungen zu einer?

Ich habe eine Tabelle mit vielen Zeilen und Spalten natürlich: P Lets sagen, es sieht wie folgt aus:

 AAA BBB CCC DDD 
----------------------- 
Row1 | 1 A D X 
Row2 | 2 B C X 
Row3 | 3 C D Z 

Jetzt habe ich eine erweiterte select-Anweisung erstellen möchten, die mir diese Kombination (pseudo SQLish gibt hier):

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' 

Der Ausgang wäre:

Test1, 1, A, D, X 
Test2, 2, B, C, X 

Wie würde ich diese beiden Select-Anweisungen in einer netten Select-Anweisung kombinieren?

Würde es funktionieren, wenn ich das SQL wie unten komplizierter mache (weil meine eigene SQL-Anweisung eine exist-Anweisung enthält)? Ich möchte nur wissen, wie ich die Auswahl kombinieren kann und dann versuche, sie auf mein etwas fortgeschritteneres SQL anzuwenden.

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...) 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...) 




Meine REAL SQL-Anweisung ist diese:

select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

was mich zu einem Resultat. Aber ich möchte es mit einer Kopie dieser Select-Anweisung mit einem hinzugefügten AND am Ende kombinieren, und das Feld 'Status' würde mit einer Zeichenfolge wie 'DELETED' geändert werden.

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
+1

+1 das ist eine sehr gut gestellte Frage –

Antwort

55

Sie haben zwei Möglichkeiten hier. Die erste ist, zwei Ergebnismengen zu haben, die ‚Test1‘ gesetzt werden oder ‚Test2‘ auf der Grundlage der Bedingung in der WHERE Klausel, und sie dann UNION zusammen:

select 
    'Test1', * 
from 
    TABLE 
Where 
    CCC='D' AND DDD='X' AND exists(select ...) 
UNION 
select 
    'Test2', * 
from 
    TABLE 
Where 
    CCC<>'D' AND DDD='X' AND exists(select ...) 

Dies könnte ein Problem sein, weil du gehst, zweimal effektiv auf TABELLE scannen/suchen.

Die andere Lösung wäre aus der Tabelle einmal wählen sein, und stellen Sie ‚Test1‘ oder ‚Test2‘ auf der Grundlage der Bedingungen in der Tabelle:

select 
    case 
     when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1' 
     when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2' 
    end, 
    * 
from 
    TABLE 
Where 
    (CCC='D' AND DDD='X' AND exists(select ...)) or 
    (CCC<>'D' AND DDD='X' AND exists(select ...)) 

Der hier Fang ist, dass Sie die duplizieren haben Filterbedingungen in der CASE Anweisung und der WHERE Anweisung.

+0

Danke (im mit MS SQL Server 2005). Scheint so, als ob ich das suche. UNION scannt zweimal, aber damit kann ich leben. Und ich wusste nicht, dass die CASE-Anweisung so schnell verwendet werden könnte. – Wolf5

9

Wenn sie aus derselben Tabelle sind, glaube ich UNION der Befehl, den Sie suchen.

(Wenn Sie jemals Werte aus Spalten verschiedener Tabellen auszuwählen bräuchten, sollten Sie bei JOIN suchen stattdessen ...)

1
select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

UNION 

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 

Vielleicht würde es tun. Ich kann es jedoch von hier aus nicht testen, und ich bin mir nicht sicher, gegen welche Version von SQL Sie arbeiten.

1

einen Fall, in die Auswahl verwenden und in der Nähe, wo einem OR

so etwas, ich habe es nicht getestet, aber es sollte funktionieren, denke ich ...

select case when CCC='D' then 'test1' else 'test2' end, * 
from table 
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X') 
1

I denke, das, was Sie suchen:

SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.* 
FROM WorkItems t1 
WHERE (TextField01, TimeStamp) IN(
    SELECT TextField01, MAX(TimeStamp) 
    FROM WorkItems t2 
    GROUP BY t2.TextField01 
) 
AND TimeStamp > '2009-02-12 18:00:00' 

Wenn Sie in Oracle oder MS SQL 2005 sind und oben, dann könnten Sie tun:

SELECT * 
FROM (
    SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*, 
    ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn 
    FROM WorkItems t1 
) to 
WHERE rn = 1 

, es ist effizienter.

2

Danke für die Eingabe. Versucht, die Sachen, die hier erwähnt wurden, und diese sind die 2 Ich habe zu arbeiten: die zweite, da es nur Scans:

(
select 'OK', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND (BoolField05=1) 
) 
UNION 
(
select 'DEL', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
) 

UND

select 
    case 
     when 
      (BoolField05=1) 
    then 'OK' 
    else 'DEL' 
     end, 
     * 
from WorkItems t1 
Where 
      exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
      AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
      AND TimeStamp>'2009-02-12 18:00:00' 

Welches ist die effizienteste dieser (bearbeiten würde der Tisch einmal), und ist es möglich, es noch effizienter zu machen? (Die BoolField = 1) ist wirklich eine Variable (dyn sql), die jede where-Anweisung in der Tabelle enthalten kann.

Ich bin auf MS SQL 2005 ausgeführt. Versuche Quassnoi Beispiele aber nicht wie erwartet funktioniert.

+0

Dies ist solide. Danke :) – Jordon

0
select t1.* from 
(select * from TABLE Where CCC='D' AND DDD='X') as t1, 
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2 

Eine andere Möglichkeit dies zu tun!

+0

Einfacher Test einer einzelnen Spalte Tabelle mit 2 Zeilen und mit dieser Abfrage die erste als t1 und zweite als t2 auswählen, schlägt fehl, gibt nur t1 zurück. – Wolf5