wake-up-neo.com

Wie füge ich 2 select-Anweisungen in einer zusammen?

Ich bin ein Noob wenn es um SQL-Syntax geht. 

Ich habe natürlich eine Tabelle mit vielen Zeilen und Spalten: P Sagen wir, es sieht so aus:

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

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

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

Die Ausgabe wäre:

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

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

Würde es funktionieren, wenn ich die SQL wie folgt kompliziert mache (weil meine eigene SQL-Anweisung eine Existenz-Anweisung enthält)? Ich möchte nur wissen, wie ich die Selects kombinieren und dann versuchen kann, sie auf meine etwas fortgeschrittenere 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 lautet:

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'

das gibt mir ein Ergebnis. Ich möchte es jedoch mit einer Kopie dieser select-Anweisung mit einem hinzugefügten AND am Ende verbinden und das 'Status'-Feld würde mit einer Zeichenfolge wie' DELETED 'geändert.

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)
43
Wolf5

Sie haben hier zwei Möglichkeiten. Die erste besteht darin, zwei Ergebnismengen zu haben, die 'Test1' oder 'Test2' basierend auf der Bedingung in der WHERE-Klausel festlegen, und 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 kann ein Problem sein, da Sie TABLE effektiv zweimal scannen/suchen werden.

Die andere Lösung wäre, einmal aus der Tabelle auszuwählen und "Test1" oder "Test2" basierend auf den Bedingungen in TABLE festzulegen:

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 Haken dabei ist, dass Sie die Filterbedingungen in der CASE-Anweisung und der WHERE-Anweisung duplizieren müssen.

58
casperOne

Wenn sie aus derselben Tabelle stammen, denke ich, dass UNION der Befehl ist, nach dem Sie suchen.

(Wenn Sie jemals Werte aus Spalten verschiedener Tabellen auswählen müssen, sollten Sie stattdessen nach JOIN suchen ...)

9
Tomas Aschan

Danke für die Eingabe. Ich habe das Zeug ausprobiert, das hier erwähnt wurde und dies sind die 2, die ich zur Arbeit bekam:

(
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 wäre das effizienteste (edit: das zweite, da die Tabelle nur einmal gescannt wird), und ist es möglich, es noch effizienter zu machen ? (The BoolField = 1) ist wirklich eine Variable (dyn sql), die eine where-Anweisung in der Tabelle enthalten kann.

Ich arbeite unter MS SQL 2005. Versuchte Quassnoi-Beispiele, funktionierte jedoch nicht wie erwartet.

3
Wolf5

Der Union-Befehl ist das, was Sie brauchen. Wenn dies nicht funktioniert, müssen Sie möglicherweise Ihre Umgebung verfeinern.

1
JB King

verwenden Sie einen Fall in der Auswahl und verwenden Sie in dem Schließen ein ODER

so etwas habe ich 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
Fredou

Ich denke, das ist, wonach 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 sich in Oracle oder MS SQL 2005 oder höher befinden, können Sie Folgendes 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.

1
Quassnoi
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 das den Trick tun. Ich kann es hier jedoch nicht testen, und ich bin mir nicht sicher, mit welcher Version von SQL Sie arbeiten.

1
Kezzer
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
arthur bryant