Pot utiliza declarația CASE într-o condiție JOIN? (Programare, Sql, Server Sql, A Se Alătura, Caz)

Doar un cursant a intrebat.

Următoarea imagine face parte din Microsoft SQL Server 2008 R2 System Views. Din imagine se poate observa că relația dintre sys.partitions și sys.allocation_units depinde de valoarea lui sys.allocation_units.type. Așadar, pentru a le uni, aș scrie ceva asemănător cu acest lucru:

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 

Dar codul de sus dă o eroare de sintaxă. Presupun că asta se datorează faptului că CASE declarație. Poate cineva să mă ajute să explice un pic?


Adăugați un mesaj de eroare:

Msg 102, Level 15, State 1, Line 6 Sintaxă incorectă lângă ‘=’.

Comentarii

    41

  • Ce software ați folosit pentru a realiza această frumoasă diagramă DB? –  > Por LearnByReading.
  • @LearnByReading ai aflat vreodată ce software a fost folosit? –  > Por Preston.
  • @User632716 nu, din păcate, nu! –  > Por LearnByReading.
  • @User632716 Deși chiar cred că a fost MySQL Workbench. Dar nu am primit niciodată un răspuns –  > Por LearnByReading.
  • @LearnByReading Nu am nicio idee. Este furnizat de Microsoft. –  > Por Doar un cursant.
9 răspunsuri
HABO

A CASE expresie returnează o valoare din THEN parte a clauzei. Ai putea să o folosești astfel:

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

Rețineți că trebuie să faceți ceva cu valoarea returnată, de exemplu, să o comparați cu 1. Instrucțiunea dvs. a încercat să returneze valoarea unei atribuiri sau să testeze egalitatea, niciuna dintre acestea neavând sens în contextul unei expresii. CASE/THEN clauză. (Dacă BOOLEAN era un tip de date, atunci testul de egalitate ar fi avut sens).

Comentarii

  • @HABO mulțumesc că a funcționat pentru mine…dar problema este că atunci când fac acest lucru condițiile fac o cădere…vă rog să-mi spuneți cum o rup? –  > Por Sagar Tandel.
  • @SagarTandel – Îmi pare rău, nu înțeleg „face o cădere prin” și „cum o rup”. Ați putea să vă clarificați comentariul? (Recent a ieșit la suprafață după o scufundare în largul Saba. Poate fi Nitrox-ul) – -.  > Por HABO.
  • Verifică toate condițiile pe care nu le vreau. Vreau să iasă din caz odată ce se potrivește cu o condiție. –  > Por Sagar Tandel.
  • @SagarTandel – De la MSDN: „Instrucțiunea CASE își evaluează condițiile în mod secvențial și se oprește la prima condiție a cărei condiție este îndeplinită.”. Dacă doriți toate rândurile alăturate care nu se potrivesc cu niciuna dintre condițiile declarate în mod explicit, trebuie doar să schimbați capătul cozii din = 1 în = 0, , dar nu cred că vă va plăcea rezultatul. –  > Por HABO.
  • 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 ați putea să scrieți în Entity framework soluția de mai sus a soluției dvs.  > Por r.hamd.
Niranjan Singh

În schimb, pur și simplu faceți JOIN la ambele tabele, iar în clauza SELECT, returnați datele din cea care se potrivește:

Vă sugerez să parcurgeți acest link Îmbinări condiționate în SQL Server și Declarația de caz T-SQL într-o clauză JOIN ON

De exemplu.

    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 

Editare: Conform comentariilor.

Nu puteți specifica condiția de îmbinare așa cum faceți… Verificați interogarea de mai sus, care nu are nicio eroare. Am scos coloana comună și valoarea coloanei din dreapta va fi evaluată în funcție de condiție.

Comentarii

  • ce conditional join înseamnă? Fiecare îmbinare (cu excepția încrucișării) este o condiție. Cum diferă acest caz de oricare altul? Exemplul dvs. are o îmbinare interioară cu condiție, la fel ca și interogarea OPs are o îmbinare cu condiție. –  > Por zerkms.
  • @zerkms: Sunt de acord, pare confuz. Cred că un îmbinare condiționată în acest context înseamnă o îmbinare a cărei condiție depinde de o altă condiție. –  > Por Andriy M.
  • @Andriy M: vreun motiv pentru a ne gândi la un alt termen pentru condiția trivială cu OR? –  > Por zerkms.
  • @zerkms: Ăăă, da, pentru că sună confuz 🙂 Dar cred că ai vrut să întrebi dacă există vreun motiv nu gândiți la un alt termen, caz în care nu pot fi sigur. Dacă întrebați pentru meu motive, ei bine, cred că pur și simplu nu m-am putut deranja suficient. 🙂 Ce ziceți de un join cu condiții alternative? Mă tem că nu mă pricep prea bine la inventarea termenilor. Rețineți, totuși, că din punct de vedere conceptual este vorba despre „condiție condiționată”, nu despre „condiție cu OR„. Folosind OR este doar o modalitate de implementare a acesteia. –  > Por Andriy M.
  • @Andriy M: ok. Dar, personal, tot nu văd motivul pentru a da un nume pentru trivial condiție cu 1 OR și 2 ANDs sau cu 1 CASE. Este o interogare de rutină care nu are nimic care să o deosebească de oricare alta. –  > Por zerkms.
richardtallent

Încearcă asta:

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

Comentarii

  • Chiar dacă ar funcționa – interogarea din întrebare pare perfect validă. Deci, tot nu explică ce este în neregulă cu codul lui OP –  > Por zerkms.
DonkeyKong

Cred că ai nevoie de două declarații case:

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             

Acest lucru se datorează faptului că:

  • instrucțiunea CASE returnează o singură valoare la sfârșit.
  • instrucțiunea ON compară două valori
  • instrucțiunea CASE efectua comparația. în interiorul a instrucțiunii CASE. Cred că, dacă ați plasa instrucțiunea CASE în SELECT, ați obține un boolean „1” sau „0”, indicând dacă instrucțiunea CASE a fost evaluată ca fiind adevărată sau falsă.

Gont

Am luat exemplul tău și l-am editat:

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
           ELSE NULL
           END)

Ștefan Gabor

Da, se poate. Iată un exemplu.

SELECT a.*
FROM TableA a
LEFT OUTER JOIN TableB j1 ON  (CASE WHEN LEN(COALESCE(a.NoBatiment, '')) = 3 
                                THEN RTRIM(a.NoBatiment) + '0' 
                                ELSE a.NoBatiment END ) = j1.ColumnName 

Comentarii

  • Deși acest cod poate rezolva întrebarea, includerea unei explicații despre cum și de ce rezolvă problema ar ajuta cu adevărat la îmbunătățirea calității mesajului dvs. și, probabil, ar duce la mai multe voturi pozitive. Nu uitați că răspundeți la întrebare pentru cititorii din viitor, nu doar pentru persoana care o pune acum. Vă rugăm să vă editați răspunsul pentru a adăuga explicații și pentru a da o indicație cu privire la limitările și ipotezele care se aplică. –  > Por dublu bip.
user4584103

Asta pare drăguț

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

Comentarii

  • Încercând acest lucru, primesc o eroare: Numele corelației „xx” este specificat de mai multe ori într-o clauză FROM. –  > Por Etienne.
Kenneth Wilson

Am preluat exemplul lui DonkeyKong.

Problema este că trebuia să folosesc o variabilă declarată. Aceasta permite declararea părții stângi și a părții drepte a ceea ce trebuie să comparați. Acest lucru este pentru a susține un raport SSRS în care diferite câmpuri trebuie să fie legate în funcție de selecția utilizatorului.

Cazul inițial stabilește alegerea câmpului pe baza selecției și apoi pot seta câmpul pe care trebuie să îl compar pentru îmbinare.

O a doua instrucțiune de caz poate fi adăugată în partea dreaptă, dacă este necesar ca variabila să aleagă din diferite câmpuri

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

Sheikh Kawser

Aici am comparat diferența în două seturi de rezultate diferite:

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