PDA

Ver la Versión Completa : LEFT INNER JOIN & RIGHT INNER JOIN


Cabanyaler
03-11-2005, 13:20:44
Hola, veamos.
Tengo un problema que se me está agrandando por motivos del normalizado de la BBDD y de la gran cantidad de filtros o campos por los que puede y desea consultar el usuario.
Expongo de manera resumidísima:Quiero hacer una consulta sobre dos tablas donde cada una de ellas posee sus claves principales y la esclava con su clave ajena refrenciando a la principal. (hasta aquí todo normal).
Una de las consultas posibles es:

SELECT A.*
FROM A
LEFT OUTER JOIN B
ON B.CAjena = A.CPrincipal

ok!, esto debería devolver todas las tuplas que existen en A independientemente de valores, ya que no establezco clausula WHERE. Pero me retorna sólo todas las tuplas de A que tienen relación con alguna tupla de B.

Mi deseo es obtener todas las tuplas de A, tengan o no tengan tuplas relacionadas en B.

Obviamente he resumido la consulta, ya que para eso haría SELECT * FROM A, pero lo que deseo es poder consultar tablas relacionadas con el INNER JOIN y que me retorne todas las de la maestra que cumplan los filtros establecidos sobre las tuplas esclavas y ademas las tuplas de la maestra que NO TENGAN ninguna tupla relacionada en la esclava.

Espero haberlo expuesto de forma entendible.
Gracias por vuestra ayuda y un saludo.

Neftali [Germán.Estévez]
03-11-2005, 14:02:51
Una de las consultas posibles es:
SELECT A.*
FROM A
LEFT OUTER JOIN B
ON B.CAjena = A.CPrincipal
ok!, esto debería devolver todas las tuplas que existen en A independientemente de valores, ya que no establezco clausula WHERE. Pero me retorna sólo todas las tuplas de A que tienen relación con alguna tupla de B.
Eso devuelve todas las tuplas de A tengan o no relación con B.
Si no es así es porque se eliminan por otro sitio, pruebalo con dos tablas simples y verás como sí (supongo que al resumir la consulta te has dejado alguna cosa importante).


Mi deseo es obtener todas las tuplas de A, tengan o no tengan tuplas relacionadas en B.
Para eso justo está el LEFT JOIN.

...pero lo que deseo es poder consultar tablas relacionadas con el INNER JOIN y que me retorne todas las de la maestra que cumplan los filtros establecidos sobre las tuplas esclavas y ademas las tuplas de la maestra que NO TENGAN ninguna tupla relacionada en la esclava.
Lo uno contradice lo otro. INNER JOIN te devolverá sólo las tuplas que existan en ambas tablas por definición.

Cabanyaler
03-11-2005, 16:30:41
Lo primero gracias.

Sí, eso entiendo que es el resultado del LEFT INNER JOIN, pero sin resumir la consulta y a falta de las declaraciones de los parametros, expongo la consulta completa:

SELECT
Contratos.*

FROM
Contratos

/* Uno por C.Aj con Clientes y estos con TelefonosCli*/
LEFT OUTER JOIN
Clientes LEFT OUTER JOIN TelefonosCli
ON TelefonosCli.CodCli_TelCli = Clientes.CodAut_Cli
ON Clientes.CodAut_Cli = Contratos.CodCli_Con

WHERE
(
( (Contratos.NumCon_Con LIKE '%' + @NumCon_sp + '%' )
AND (Contratos.FecCon_Con >= @FecIniCon_sp AND Contratos.FecCon_Con <= @FecFinCon_sp)
AND (Contratos.FecEnt_Con >= @FecIniEnt_sp AND Contratos.FecEnt_Con <= @FecFinEnt_sp)
AND (Contratos.TipCon_Con LIKE '%' + @TipCon_sp + '%')
AND (Contratos.ExeCon_Con = @ExeCon_sp)
AND (Contratos.MotExe_Con LIKE '%' + @MotExe_sp + '%')
AND (Contratos.Obs2Con_Con LIKE '%' + @Obs2Con_sp + '%')
AND (Contratos.DesPro_Con LIKE '%' + @DesPro_sp + '%')
AND (Contratos.FecAvi_Con >= @FecIniAvi_sp AND Contratos.FecAvi_Con <= @FecFinAvi_sp)
AND (Contratos.TotCon_Con >= @TotConIni_sp AND Contratos.TotCon_Con <= @TotConFin_sp)
AND (Contratos.EntCeg_Con = @EntCeg_sp)
AND (Contratos.EntDis_Con = @EntDis_sp)
AND ((Contratos.ObsCon_Con LIKE '%' + @ObsCon_sp + '%') OR (Contratos.ObsCon_Con IS NULL))
)

AND

((Clientes.TipVia_Cli LIKE '%' + @TipVia_sp + '%') /* Tots els Clientes que pasen els filtres amb determinat TelefonoCli*/
AND (Clientes.DirCli_Cli LIKE '%' + @DirCli_sp + '%')
AND (Clientes.NumPto_Cli LIKE '%' + @NumPto_sp + '%')
AND (Clientes.NumPta_Cli LIKE '%' + @NumPta_sp + '%')
AND (Clientes.EscCli_Cli LIKE '%' + @EscCli_sp + '%')
AND (Clientes.NomCli_Cli LIKE '%' + @NomCli_sp + '%')
AND (Clientes.DniCli_Cli LIKE '%' + @DniCli_sp + '%')
AND (Clientes.LetCif_Cli LIKE '%' + @LetCif_sp + '%')
AND (Clientes.PobCli_Cli LIKE '%' + @PobCli_sp + '%')
AND (Clientes.CodPos_Cli LIKE '%' + @CodPos_sp + '%')
AND (Clientes.RefCli_Cli LIKE '%' + @RefCli_sp + '%')
AND (Clientes.CodCli_Cli LIKE '%' + @CodCli_sp + '%'))
AND TelefonosCli.NumTel_telCli LIKE '%' + @NumTel_sp + '%'
)

ORDER BY Contratos.TipCon_Con


Esto debería retornar todas las tuplas de la tabla Contratos que cumplen las condiciones del WHERE propias de los Contratos además de que las tuplas del Cliente asociado que cumplan tambien las condiciones del WHERE de los Clientes y el telefono del cliente tambien pase el filtro . Además de todos los Contratos que por estar unidos por el LEFT INNER JOIN no tengan o bien clientes o clientes sin telefono.

¿NO? :confused: Créeme, ójala esté equivocado!!

Neftali [Germán.Estévez]
03-11-2005, 17:10:28
...Además de todos los Contratos que por estar unidos por el LEFT INNER JOIN no tengan o bien clientes o clientes sin telefono.
A éstos también se les aplica el filtro. ¿A ver si los nulos no te están pasando los filtros y ahí es donde se te quedan?

Cabanyaler
03-11-2005, 17:37:39
No, ufffff, no tengo valores nulos .Ya había valorado esta opción, aunque la he vuelto a considerar.

Lo único que me retorna (pasando todos los parametros vacios, menos el del Contratos.ExeCon_Con = @ExeCon_sp) son aquellos contratos que tienen clientes y que estos clientes tienen teléfono, en el caso de no tener teléfono, no los muestra. :(

Esto me está llevando a realizar diferentes consultas según los parametros que pase con valor además de que tablas necesite consultar, creciéndome exponencialmente las consultas a razón de las combinaciones de todas las tablas relacionadas con los contratos o alguna tabla esclava de estos.

Por ejemplo, si quiero que la consulta me retorne todos los contratos con cliente independientemente del número de teléfono, es decir, tenga teléfono con cualquier número o no tenga teléfono ese determinado cliente del contrato, escribo la misma consulta pero sin el INNER JOIN de relación con el contrato:

...
FROM
Contratos
LEFT OUTER JOIN
Clientes ON Clientes.CodAut_Cli = Contratos.CodCli_Con
en lugar de:
...
FROM
Contratos
LEFT OUTER JOIN
Clientes LEFT OUTER JOIN TelefonosCli
ON TelefonosCli.CodCli_TelCli = Clientes.CodAut_Cli
ON Clientes.CodAut_Cli = Contratos.CodCli_Con


En fin... :( :( No veas el lio y el curro combinacinal que tengo.

jachguate
03-11-2005, 18:23:43
Que tal.

Veo un grave problema de concepto por aqui.

Estas mandando pedir todos los contratos, tengan o no cliente, pero luego filtras aquellos cuya dirección (del cliente) sea similar a x.

Si no hay cliente, ¿cómo su dirección podría ser similar a algo?

Otro asunto es la versión de sqlserver que estas utilizando, puesto que antes del 2000, si no mal recuerdo, el comportamiento con los filtros y los encuentros externos era erratico, pues el motor filtraría registros que si pasan por el where con que solo se referenciara la tabla externa en dicha clausula.

Lo dejaré hasta alli, pues no he leido toda la consulta, principalmente por no estar publicada con la etiqueta [ sql ], que facilitaría en mucho su rápida comprensión, y porque después de un par de años por aqui, me parece imprescindible que la uses.

Hasta luego.

;)

Cabanyaler
04-11-2005, 09:58:46
Hola, antes de nada agradecerte tu interés. Disculpa por no ponerlo como [code] o [sql], no conocía la etiqueta. Y no son dos años por aquí, son más lo que ocurre es que perdí la antiguedad al darme de alta de nuevo cuando cambió la página del foro.
Veamos.

Con respecto a lo que me comentas en tu observación:

Estas mandando pedir todos los contratos, tengan o no cliente, pero luego filtras aquellos cuya dirección (del cliente) sea similar a x.

Si no hay cliente, ¿cómo su dirección podría ser similar a algo?

Si es cierto que quiero todos los contratos, independientemente de si tiene cliente o si teniendo cliente independientemente de si este a su vez tiene teléfono etc. Pero, ¿de eso no se encarga precisamente el LEFT INNER JOIN?, de retornar todos los contratos tengan o no cliente o todos los clientes con contrato tengan o no teléfono, y si lo tienen aplicarles las clausulas WHERE? :(

Por cierto y retomando lo de las etiquetas, ¿como puedo incluir el texto coloreado en verde como una cita de tu anterior respuesta?.

Gracias a todos.

__hector
04-11-2005, 13:35:31
Arriba Barςa!!

lucasarts_18
04-11-2005, 18:06:36
Por cierto y retomando lo de las etiquetas, ¿como puedo incluir el texto coloreado en verde como una cita de tu anterior respuesta?.

Gracias a todos.
Al momento de responder tienes al lado derecho, en la parte inferior un botón llamado Citar...

O bien a traves de las etiquetas Quote.

Ejemplo
[QUOTE=minombre].......[/QUOTE..

No he cerrado el último corchete o sino no me aparece nada, pero al momento de citar si debes hacerlo!!.

Hasta Luego -

jachguate
05-11-2005, 00:56:23
Si es cierto que quiero todos los contratos, independientemente de si tiene cliente o si teniendo cliente independientemente de si este a su vez tiene teléfono etc. Pero, ¿de eso no se encarga precisamente el LEFT INNER JOIN?, de retornar todos los contratos tengan o no cliente o todos los clientes con contrato tengan o no teléfono, y si lo tienen aplicarles las clausulas WHERE? :(

¿left inner join?. No lo creo. Será un left outer join :D.

Efectivamente, el left outer join se encarga de traer todos los contratos, independientemente de si tienen cliente o no. Podes comprobarlo quitando de la clausula where todo lo que haga referencia a campos de la tabla cliente o teléfono.

El problema se da precisamente cuando NO hay un cliente, pues tu clausula where se encarga de filtrar TODOS estos registros, pues no prevee ninguna condición que los deje pasar.

Dado que el left join devolverá null para todos los campos de la tabla cliente cuando no exista un registro asociado a esta, lo usual es incluir en el where los correspondientes "or's" para que deje "pasar" estos registros, algo como:

select f.*, c.*
from factura f
left outer join cliente c on c.idcliente = f.id_cliente
where (c.ciudad = 'GUATEMALA' OR c.ciudad is null)
and (c.apellido like '%CASTILLO%' or c.apellido is null);


Esto devolverá todas las facturas para clientes con apellido CASTILLO de la ciudad de guatemala y todas aquellas que no tengan asociado un cliente.

Hasta luego.

;)

Cabanyaler
07-11-2005, 16:17:36
Hola, gracias por todo. Voy a probrarlo, pero no entiendo porque de :


que el left join devolverá null para todos los campos de la tabla cliente cuando no exista un registro asociado a esta, lo usual es incluir en el where los correspondientes "or's" para que deje "pasar" estos registros,

pero si en realidad hace eso internamente, nadie somos nosotros pobres mortales para cuestionar el funcionamiento interno de la santa madre. ;)

Ya digo en que he quedado.

Cabanyaler
07-11-2005, 18:09:58
Correcto.
Pero por la propia idiosincrasia de los resultados que busco aún así me veo obligado a la combinatoria de LEFT OUTER JOIN con unas tablas o no.
Gracias por vuestra ayuda, colaboración e interes.
Força.