web-dev-qa-db-fra.com

Comment sélectionner plusieurs colonnes dans un CASE WHEN sur SQL Server?

J'ai effectué des recherches approfondies sur ce site, mais je ne trouve pas de solution.

Voici l'exemple de ma requête:

SELECT 
   ActivityID,

   Hours = (CASE 
                WHEN ActivityTypeID <> 2 THEN
                     FieldName = (Some Aggregate Sub Query),
                     FieldName2 = (Some other aggregate sub query)
                WHEN ActivityTypeID = 2 THEN
                     FieldName = (Some Aggregate Sub Query with diff result),
                     FieldName2 = (Some Other Aggregate Sub Query with diff result)
           END)

évidemment je laisse de côté une grande partie de la requête, je voulais juste voir si c'était possible.

Je sais que je pourrais probablement faire le "CASE" deux fois mais je me suis dit que je demanderais ...

24
Joshua

Le problème est que l'instruction CASE ne fonctionnera pas de la même manière que vous essayez de l'utiliser. Vous ne pouvez l'utiliser que pour changer la valeur d'un champ dans une requête. Si je comprends ce que vous essayez de faire, vous pourriez avoir besoin de ceci:

SELECT 
   ActivityID,
   FieldName = CASE 
                  WHEN ActivityTypeID <> 2 THEN
                      (Some Aggregate Sub Query)
                  ELSE
                     (Some Aggregate Sub Query with diff result)
               END,
   FieldName2 = CASE
                  WHEN ActivityTypeID <> 2 THEN
                      (Some Aggregate Sub Query)
                  ELSE
                     (Some Aggregate Sub Query with diff result)
               END
28
Josh Anderson

Non, CASE est une fonction et ne peut renvoyer qu'une seule valeur. Je pense que vous allez devoir dupliquer votre logique CASE.

L'autre option consisterait à envelopper la requête entière avec un IF et à avoir deux requêtes distinctes pour renvoyer les résultats. Sans voir le reste de la requête, il est difficile de dire si cela fonctionnerait pour vous.

13
Pete McKinney

"Case" peut renvoyer une seule valeur, mais vous pouvez utiliser un type complexe:

create type foo as (a int, b text);
select (case 1 when 1 then (1,'qq')::foo else (2,'ww')::foo end).*;
1
Ghost

En fait, vous pouvez le faire.

Bien que quelqu'un devrait noter que répéter les déclarations CASE n'est pas si mal qu'il y paraît. L'optimiseur de requêtes de SQL Server est suffisamment intelligent pour ne pas exécuter la CASE afin de ne pas nuire aux performances à cause de cela. 

De plus, quelqu'un pourrait utiliser la logique suivante pour ne pas répéter le CASE (si cela vous convient ..)

INSERT INTO dbo.T1
(
    Col1,
    Col2,
    Col3
)
SELECT
    1,
    SUBSTRING(MyCase.MergedColumns, 0, CHARINDEX('%', MyCase.MergedColumns)),
    SUBSTRING(MyCase.MergedColumns, CHARINDEX('%', MyCase.MergedColumns) + 1, LEN(MyCase.MergedColumns) - CHARINDEX('%', MyCase.MergedColumns))
FROM
    dbo.T1 t
LEFT OUTER JOIN
(
    SELECT CASE WHEN 1 = 1 THEN '2%3' END MergedColumns
) AS MyCase ON 1 = 1

Cela insérera les valeurs (1, 2, 3) pour chaque enregistrement de la table T1. Ceci utilise un délimiteur '%' pour fractionner les colonnes fusionnées. Vous pouvez écrire votre propre fonction de partage en fonction de vos besoins (par exemple, pour gérer des enregistrements nuls ou utiliser un délimiteur complexe pour les champs varchar, etc.). Mais la logique principale est que vous devez joindre l'instruction CASE et sélectionner dans l'ensemble de résultats de la jointure en utilisant une logique de division.

0
sotn