web-dev-qa-db-fra.com

Comment combiner 2 déclarations en une?

Je suis un noob en matière de syntaxe SQL. 

J'ai un tableau avec beaucoup de lignes et de colonnes de cours: P Disons qu'il ressemble à ceci:

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

Maintenant, je veux créer une instruction select avancée qui me donne cette combinaison (pseudo SQLish ici):

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

La sortie serait:

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

Comment pourrais-je combiner ces deux instructions select en une seule instruction select Nice?

Cela fonctionnerait-il si je compliquais le SQL comme ci-dessous (parce que ma propre instruction SQL contient une instruction existe)? Je veux juste savoir comment je peux combiner les sélections, puis essayer de l'appliquer à mon SQL un peu plus avancé.

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 ...)




Mon instruction REAL SQL est la suivante:

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'

ce qui me donne un résultat. Mais je veux le combiner avec une copie de cette instruction select avec un AND ajouté à la fin et le champ "Status" serait modifié avec une chaîne comme "DELETED".

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

Vous avez deux choix ici. La première consiste à avoir deux jeux de résultats définissant 'Test1' ou 'Test2' en fonction de la condition de la clause WHERE, puis UNION ensemble:

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 ...)

Cela peut être un problème, car vous allez scanner/rechercher efficacement sur TABLE deux fois.

L'autre solution consisterait à sélectionner une fois dans le tableau et à définir "Test1" ou "Test2" en fonction des conditions du TABLEAU:

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 ...))

Le problème ici est que vous devrez dupliquer les conditions de filtre dans les instructions CASE et WHERE.

58
casperOne

Si elles proviennent de la même table, je pense que UNION est la commande que vous recherchez.

(Si vous aviez besoin de sélectionner des valeurs dans les colonnes de différentes tables, vous devriez regarder JOIN à la place ...)

9
Tomas Aschan

Merci pour la contribution. Essayé les trucs qui ont été mentionnés ici et ce sont les 2 je dois travailler:

(
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)
)

ET

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'

Laquelle serait la plus efficace (edit: la seconde car elle n’analyse la table qu’une fois), et est-il possible de la rendre encore plus efficace ? (BoolField = 1) est en réalité une variable (dyn sql) pouvant contenir n’importe quelle instruction where de la table.

Je cours sur MS SQL 2005. J'ai essayé des exemples de Quassnoi, mais cela n’a pas fonctionné comme prévu.

3
Wolf5

La commande de l'Union est ce dont vous avez besoin. Si cela ne fonctionne pas, vous devrez peut-être préciser dans quel environnement vous vous trouvez.

1
JB King

utiliser un cas dans la sélection et utiliser dans où fermer un OU

quelque chose comme ça, je ne l’ai pas testé mais ça devrait marcher, je pense ...

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

Je pense que c'est ce que vous cherchez:

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'

Si vous êtes dans Oracle ou dans MS SQL 2005 et versions supérieures, vous pouvez alors effectuer les tâches suivantes:

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

, c'est plus efficace.

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)

Peut-être que ça ferait l'affaire. Cependant, je ne peux pas le tester à partir d'ici, et je ne suis pas sûr de la version de SQL sur laquelle vous travaillez.

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

Une autre façon de faire ça!

0
arthur bryant