Duda consulta SQL

  • Iniciador del tema Iniciador del tema moshano
  • Fecha de inicio Fecha de inicio

moshano

Miembro
1.204 mensajesdesde 2002
2 agradecimientos
A ver si me podeis echar una mano que ando un poco espeso. Tengo que hacer una consulta sobre tres tablas, dos de ellas (B y C) "hijas"de la principal (A) a través del campo "código" común a las tres (no hay relación creada en la BBDD). El caso es que los registros "hijo" o bien están en B o en C, pero no en las dos a la vez.

Ejemplo:

Tabla A: codigo / nombre / .....
Tabla B: codigo/ calle / ....
Tabla C: codigo / carretera / ....

Si por ejemplo el registro "hijo" estuviese en B, necesitaría obtener: codigo/nombre/calle. Si estuviese en C sería codigo/nombre/carretera. Lo ideal sería que no me apareciesen en blanco los campos de la tabla (B o C) que no tuviese el registro, es decir, si pudiese obtener un resultado codigo/nombre/direccion y en dirección ir teniendo la calle o carretera según corresponda sería cojonudo. Todo ello, como os dije, en una única consulta.

No sé si me he explicado bien, pero llevo un rato dándole vueltas y de momento no lo veo :doh

Un saludo.
 
En un primer momento crei tener la solución, pero creo que es imposible lo que pides. Ya que teniendo en cuenta que en la query le pides todos los campos, a lo sumo los que no encuntre efectivamente te saldrán a nulos, pero la columna está ahi.

Tema muy distinto es que una de las columnas que solicites sea la unión de varias, de modo que si alguna no tiene nada, pues no pasa nada ya que muestra otra información. Ejemplo gilipollas:

Select A.codigo, A.nombre,A.etc, B.calle + c.carretara + ...etc
from tabla A, tabla B, tabala C
.....

... con está solución si te falla un campo, no se notará nada. ejemplo de posibles resultados:

1.- 10 | Pepe | c/ El Arbol carretera 4
2.- 11 | Juan | Carretera N-1
3.- 12 | Luis | c/ El Nabo 4

También podriamos jugar con la función decode, pero ahora me voy a fumar un cigarrillo. :hola


Un abrazo!
 
Gracias txema. El problema es cómo poner la relación entre tablas en esa consulta, con el ejemplo que me pones saldría para cada valor de codigo de A todos los registros de B y C.
Si sólo fuese sólo una tabla "hija", logicamente funcionaría perfecto con inner join, pero al ser dos no consigo que me funcione.
 
moshano dijo:
Gracias txema. El problema es cómo poner la relación entre tablas en esa consulta, con el ejemplo que me pones saldría para cada valor de codigo de A todos los registros de B y C.
Si sólo fuese sólo una tabla "hija", logicamente funcionaría perfecto con inner join, pero al ser dos no consigo que me funcione.

where A.codigo(+) = B.codigo
and A.codigo(+) = C.codigo

... Pureba con esto por ejemplo. O pon el (+) al otro lado para los campos B y C. Siento no poderte decir mucho mas, hoy estoy de resaca de fiesta.


Un abrazo!
 
Se me ocurre que podrías utilizar la función 'coalesce'. Dicha función establece en el campo el primer valor no nulo de la lista de valores posibles informados.

Posibles pruebas:
1º Efectuar un left join (definiendo como la tabla madre y como b cualquiera de las dos hijas) con el campo código.
2º definiendo dirección como: coalesce (b.calle, (select c.carretera from nombre_tercera_tabla as c where a.codigo = c.codigo)) as direccion

Otra alternativa sería no hacer ningún left join y realizar el coalesce de la siguiente forma: coalesce ((select b.calle from nombre_segunda_tabla as b where a.codigo = b.codigo), (select c.carretera from nombre_tercera_tabla as c where a.codigo = c.codigo))

Adicionalmente, también creo que se puede solucionar con la instrucción 'case .. when.. end'.

Espero te sea de ayuda, salu2.
 
Si A es única y puede tener relación con B o C pero no con las dos a la vez entonces es una unión de dos selects right inner join.

Usease:

select a.campo1, a.campo2, b.campo1
from tabla_a a join tabla_b b on a.campoclave=b.campoclave
union all
select a.campo1, a.campo2, c.campo1
from tabla_a a join tabla_c c on a.campoclave=c.campoclave

OJO: b.campo1 y c.campo1 deben ser compatibles para que el UNION ALL funcione


Aunque he de reconocer que la opción de Txema es buena siempre y cuando tengas en cuenta que un right inner join no deviuelve registro si el registro foráneo no existe. Habría que usar left join (o exception join que no es ANSI pero está en varios SGBDs) y jugar con los NULL. Suena a coñazo y lo es.

Pero vamos, la solución chorra total es la que te he puesto yo :win


Sobre la de mike88, seguro que funciona pero es un poquillo rebuscadilla :)
 
Creo que la solución de VivaerBetis es más elegante.

Es decir, las tablas B y C son complementarias ya que no tendrán registros repetidos con el mismo código por lo que dices, en ese caso lo mejor es crearse una tabla intermedia con la union de las dos.

Este es el paso uno.

Ahora lo "bonito" del sql (por cierto, de que BBDD hablamos?? no es lo mismo un oracle que un sql server) es que se puede aplicar la join a una tabla temporal.

Uso sintaxis Sql server (que es en lo que llevo años currando) para que se vea la idea, porque de oracle me acuerdo poco...


Select A.Codigo, A.Nombre, BC.Direccion
FROM tabla_a AS A
LEFT JOIN (select B.Codigo, B.Calle as Direccion
FROM tabla_b as B

UNION ALL

select C.Codigo, C.Carretera as Direccion
FROM tabla_c as C) AS BC
ON A.Codigo = BC.Codigo

Esto funciona perfectamente y además al optimizador del sql le mola mucho... :P

Si la "Dirección" no es solo la calle, puedes montarla concatenando campos siempre y cuando las dos selects de la union devuelvan siempre el mismo número de campos.
 
Sin haberlo probado ahora mismo, la solución de Txema diría que es más rápida (concatenar dos campos y hacer left joins).

Si es Oracle, concatenas campos con "||" (dos tuberías) en lugar de un símbolo "+" (de suma).

Es rarísimo que algo no se pueda hacer con una sóla sentencia SQL, por compleja que sea ésta.

Saludos.

PD: Esa BBDD está diseñada con el culo...
 
Atrás
Arriba