2011-09-01 12 views
21

Quiero poder unir dos tablas internas en función del resultado de una expresión.Conditional Inner Join

lo que he estado tratando hasta ahora:

INNER JOIN CASE WHEN RegT.Type = 1 THEN TimeRegistration ELSE DrivingRegistration AS RReg 
ON 
RReg.RegistreringsId = R.Id 

REGT es una unión que hice justo antes de esta unión:

INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id 

Este-secuencia de comandos SQL no funciona.

Así que, en total, si el Type es 1, entonces debe unirse a la tabla TimeRegistration si no debería unirse en DrivingRegistration.

Solución:

En mi instrucción de selección que realizan las siguientes uniones:

INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id 
LEFT OUTER JOIN TimeRegistration AS TReg ON TReg.RegistreringsId = R.Id AND RegT.Type = 1 
LEFT OUTER JOIN DrivingRegistration AS DReg ON DReg.RegistreringsId = R.Id AND RegT.Type <>1 

Entonces editado mi where-clause para emitir la correcta, dependiendo de la RegType, así:

WHERE (CASE RegT.Type WHEN 1 THEN TReg.RegistreringsId ELSE DReg.RegistreringsId END = R.Id) 
+0

¡No puedes hacerlo así! 'CASE' no se puede usar para intercambiar dinámicamente partes aleatorias de la consulta. ¿Estas tablas tienen las mismas estructuras? –

+0

¿Aparece un error? Si es así, ¿qué es? – AndrewC

Respuesta

18

trate de poner las dos tablas de la consulta utilizando de LEFT JOIN

LEFT JOIN TimeRegistration TR ON r.rid = TR.Id AND RegT.type =1 
LEFT JOIN DrivingRegistration DR ON r.rid = DR.Id AND RegT.type <>1 

Ahora, en selecciona cláusula, utilizar

CASE RegType.Type WHEN 1 THEN TR.SomeField ELSE DR.someField END as SomeField 

La otra opción es utilizar SQL dinámico

+0

Parece que las mentes geniales piensan igual David, simplemente escribe más rápido ... – Sparky

+0

Dedos ninja ... – David

+0

¡Impresionante, tanto las sugerencias de Sparky como las de David ayudaron! Editaré mi pregunta a lo que hice para que funcione. – KristianB

8

Es probable que deba realizar dos uniones a la izquierda, una en TimeRegistration y uno en DrivingRegistration, y devolver los campos que desee desde la apropiada tabla de unión o menos así:

LEFT JOIN TimeRegistration ON TimeRegistration.RegistreringsId = R.Id 
LEFT JOIN DrivingRegistration ON DrivingRegistration.RegistreringsId = R.Id 

y seleccione declaración sería algo como esto:

SELECT CASE WHEN RegT.Type = 1 THEN TimeRegistration.Foo ELSE DrivingRegistration.Bar END 

me gusta lo que' Estoy tratando de hacerlo, pero no creo que SQL sea tan inteligente.

1
SELECT 
    R.foo, tr.bar 
FROM 
    SomeTable AS R 
    INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id 
              AND RegT1.Type = 1 
    INNER JOIN TimeRegistration AS tr ON /* whatever */ 

UNION 

SELECT 
    R.foo, dr.bar 
FROM 
    SomeTable AS R 
    INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id 
              AND RegT1.Type = 2 
    INNER JOIN DrivingRegistration AS dr ON /* whatever */ 
+0

+1 aunque probablemente necesite ser 'UNION ALL '. Si las tablas son compatibles con Union, podrían estar en un CTE con una columna 'type' para evitar repetir la lógica' JOIN' aunque no esté seguro de cómo se verían los planes de ejecución. –

+0

@Martin: con los índices correctos, las dos uniones deben ser bastante rápidas. Supuse que dado que las dos tablas de objetivos son diferentes, un UNION ALL no sería necesario. – Tomalak