web-dev-qa-db-fra.com

Puis-je utiliser l'instruction CASE dans une condition JOIN?

L'image suivante fait partie des vues système de Microsoft SQL Server 2008 R2. L'image montre que la relation entre sys.partitions et sys.allocation_units dépend de la valeur de sys.allocation_units.type. Donc, pour les réunir, j'écrirais quelque chose de similaire à ceci:

SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id = p.hobt_id 
               WHEN a.type IN (2)
                   THEN a.container_id = p.partition_id
               END 

Mais le code supérieur donne une erreur de syntaxe. Je suppose que cela est dû à la déclaration CASE. Quelqu'un peut-il aider à expliquer un peu?


Ajouter un message d'erreur:

Msg 102, niveau 15, état 1, ligne 6 Syntaxe incorrecte près de '='.

this is the image

111
Just a learner

Une expression CASE renvoie une valeur à partir de la partie THEN de la clause. Vous pourriez l'utiliser ainsi:

SELECT  * 
FROM    sys.indexes i 
    JOIN sys.partitions p 
        ON i.index_id = p.index_id  
    JOIN sys.allocation_units a 
        ON CASE 
           WHEN a.type IN (1, 3) AND a.container_id = p.hobt_id THEN 1
           WHEN a.type IN (2) AND a.container_id = p.partition_id THEN 1
           ELSE 0
           END = 1

Notez que vous devez faire quelque chose avec la valeur renvoyée, par exemple. comparez-le à 1. Votre instruction a tenté de renvoyer la valeur d'une affectation ou d'un test d'égalité, ce qui n'a aucun sens dans le contexte d'une clause CASE/THEN. (Si BOOLEAN était un type de données, le test d'égalité aurait alors du sens.)

191
HABO

Au lieu de cela, vous vous adressez simplement aux deux tables et dans votre clause SELECT, vous retournez les données de celle qui correspond:

Je vous suggère de passer par ce lien Jointures conditionnelles dans SQL Server et Instruction de cas T-SQL dans une clause JOIN ON

par exemple.

    SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON a.container_id =
            CASE
               WHEN a.type IN (1, 3)
                   THEN  p.hobt_id 
               WHEN a.type IN (2)
                   THEN p.partition_id
               END 

Edit: Selon les commentaires.

Vous ne pouvez pas spécifier la condition de jointure comme vous le faites .. Vérifiez la requête ci-dessus qui ne contient aucune erreur. J'ai sortir la colonne commune et la valeur de la colonne de droite sera évaluée à condition.

31
Niranjan Singh

Essaye ça:

...JOIN sys.allocation_units a ON 
  (a.type=2 AND a.container_id = p.partition_id)
  OR (a.type IN (1, 3) AND a.container_id = p.hobt_id)
17
richardtallent

Je pense que vous avez besoin de deux déclarations de cas:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON 
        -- left side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id
               WHEN a.type IN (2)
                   THEN a.container_id
            END 
        = 
        -- right side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN p.hobt_id
               WHEN a.type IN (2)
                   THEN p.partition_id
            END             

Ceci est dû au fait:

  • l'instruction CASE renvoie une valeur unique à la fin
  • l'instruction ON compare deux valeurs
  • votre déclaration CASE faisait la comparaison à l'intérieur de la déclaration CASE. J'imagine que si vous mettez votre instruction CASE dans votre SELECT, vous obtenez un booléen '1' ou '0' indiquant si l'instruction CASE est évaluée à True ou à False.
8
DonkeyKong

Cela semble bien

https://bytes.com/topic/sql-server/answers/881862-joining-different-tables-based-condition

FROM YourMainTable
LEFT JOIN AirportCity DepCity ON @TravelType = 'A' and DepFrom =  DepCity.Code
LEFT JOIN AirportCity DepCity ON @TravelType = 'B' and SomeOtherColumn = SomeOtherColumnFromSomeOtherTable
1
user4584103

J'ai pris votre exemple et l'ai édité:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON CASE
           WHEN a.type IN (1, 3)
               THEN p.hobt_id 
           WHEN a.type IN (2)
               THEN p.partition_id
           ELSE NULL
           END = a.container_id
1
Gont

Ici, j'ai comparé la différence entre deux ensembles de résultats différents. J'espère que cela pourrait être utile.

SELECT main.ColumnName, compare.Value PreviousValue,  main.Value CurrentValue
FROM 
(
    SELECT 'Name' AS ColumnName, 'John' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'jh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, NULL as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) main
INNER JOIN
(
    SELECT 'Name' AS ColumnName, 'Rahul' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'rh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, '01722112233' as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) compare
ON main.ColumnName = compare.ColumnName AND
CASE 
    WHEN main.Value IS NULL AND compare.Value IS NULL THEN 0
    WHEN main.Value IS NULL AND compare.Value IS NOT NULL THEN 1
    WHEN main.Value IS NOT NULL AND compare.Value IS NULL THEN 1
    WHEN main.Value <> compare.Value THEN 1
END = 1 
0
Sheikh Kawser

Pris l'exemple de DonkeyKong.

Le problème est que je devais utiliser une variable déclarée. Cela permet d'indiquer à gauche et à droite ce que vous devez comparer. Cela permet de prendre en charge un rapport SSRS dans lequel différents champs doivent être liés en fonction de la sélection effectuée par l'utilisateur.

Le cas initial définit le choix du champ en fonction de la sélection, puis je peux définir le champ sur lequel je dois faire correspondre la jointure.

Une deuxième instruction de casse peut être ajoutée pour le côté droit si la variable est nécessaire pour choisir parmi différents champs

LEFT OUTER JOIN Dashboard_Group_Level_Matching ON
       case
         when @Level  = 'lvl1' then  cw.Lvl1
         when @Level  = 'lvl2' then  cw.Lvl2
         when @Level  = 'lvl3' then  cw.Lvl3
       end
    = Dashboard_Group_Level_Matching.Dashboard_Level_Name
0
Kenneth Wilson