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)
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.
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.
Der Union-Befehl ist das, was Sie brauchen. Wenn dies nicht funktioniert, müssen Sie möglicherweise Ihre Umgebung verfeinern.
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')
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.
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.
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!