Como hacer inner join que devuelve varias filas.

24/05/2005 - 22:49 por Jose Antonio | Informe spam
Hola grupo.

Tengo un problema con una sentencia select que se me resiste y no logro dar
con una solucion adecuada:

Tengo una tabla pisos con el codigo y la descripción, otra de Recibos con el
codigo y la descripcion.

En otra tabla lineasrecibos tengo los diferentes recibos que paga cada uno
de los pisos, de esta forma:

Pisos: idpiso int
descripcion varchar(30)


Recibos: idrecibo int
detalle varchar(40)
importe decimal(10,2)

Lineasrecibos: idpiso int
idrecibo int

cada piso tiene varias lineas en Linearecibos porque todos pagan mas de un
recibo.

En ocasiones tengo que realizar un select en el que se detalle informacion
con exclusion de uno o mas recibos.

yo hago el select asi:

select idpiso,descripcion from pisos join (select idpiso from lineasrecibos
where idrecibo not in(10)) r on r.idpiso=idpiso.

no me funciona porque si un piso paga el recibo 10 y el recibo 12 me sale la
linea del recibo 12 y necesito que si esta excluido en el in, aunque tenga
otros recibos no salga.


Saludos y gracias.

Preguntas similare

Leer las respuestas

#11 Alejandro Mesa
25/05/2005 - 19:48 | Informe spam
Jose Antonio,

Cuando usamos "not exists" en la clausula "where" de una senetencia
"select", sql server no considera la expresion como un argumento de busqueda
y claro esta que esto puede causar que la consulta sea lenta. Fijate en el
siguiente ejemplo, el plan de ejecucion entre la sentencia que usa "not
exists" y la que usa "exists". En la primera, sql server hace un scan del
indice clustered de la tabla "customers" y en la segunda hace un seek (la
operacion seek sobre un indice es la mas rapida)

use northwind
go

set showplan_text on
go

select
customerid,
companyname,
country
from
dbo.customers as c
where
not exists(
select
*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
oh.customerid = c.customerid
and od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
)

select
customerid,
companyname,
country
from
dbo.customers as c
where
exists(
select
*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
oh.customerid = c.customerid
and od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
)
go

set showplan_text off
go

Como podemos expresar esta consulta usando "join" y no "not exists"?. Esa es
una buena pregunta. Posiblemente usando una tabla derivada de los clientes
que han comprado esos productos, y hacer un "left join" entre la tabla
"customers" y la tabla derivada, filtrando el resultado para los clientes que
no machan.

select
c.customerid,
c.companyname,
c.country
from
dbo.customers as c
left join
(
select
oh.customerid
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
) as t
on c.customerid = t.customerid
where
t.customerid is null
go

bueno, ahora hay que comparar los planes de ejecucion de ambas versiones. en
mi maquina, la que usa "not exists" tiene menor costo respecto al batch.

Veamos como adaptar la sentencia relacionada con tu problema.

select
p.idpiso,
p.descripcion
from
pisos as p
left join
(
select
idpiso
from
lineasrecibos
where
idrecibo in (10, 11, 12)
) as t
on p.idpiso = t.idpiso
where
t.idpiso is null

Ahora prueba que ambas sentencias den el mismo resultado y compara los
planes de ejecucion.


AMB

"Jose Antonio" wrote:

Una pregunta:

Es normal que con la subconsulta el select sea un poco mas lento que con el
join?

Saludos
"José Antonio" escribió en el
mensaje news:
> Ok. Gracias a todos.
> "Alejandro Mesa" escribió en el
> mensaje news:
>> Trata:
>>
>> select idpiso, descripcion
>> from pisos as p
>> where not exists (
>> select *
>> from lineasrecibos as l
>> where l.idpiso = p.idpiso and idrecibo in (10, 11, 12)
>> )
>>
>>
>> AMB
>>
>> "José Antonio" wrote:
>>
>>> Es eso, pero puede ser que quiera excluir los pisos que contengan mas
>>> de un
>>> recibo.
>>>
>>> Como seria el select si quiero escluir los pisos que contengan los
>>> recibos
>>> 10,.11 y 12?
>>>
>>> Saludos
>>>
>>> "Alejandro Mesa" escribió en
>>> el
>>> mensaje news:
>>> > Jose Antonio,
>>> >
>>> > Dejame refrasear la pregunta. Quieres excluir los pisos que contengan
>>> > determinado recibo?, si es asi, entonces usa:
>>> >
>>> > select idpiso, descripcion
>>> > from pisos as p
>>> > where not exists (
>>> > select *
>>> > from lineasrecibos as l
>>> > where l.idpiso = p.idpiso and idrecibo = 10
>>> > )
>>> >
>>> >
>>> > AMB
>>> >
>>> > "Jose Antonio" wrote:
>>> >
>>> >> Hola grupo.
>>> >>
>>> >> Tengo un problema con una sentencia select que se me resiste y no
>>> >> logro
>>> >> dar
>>> >> con una solucion adecuada:
>>> >>
>>> >> Tengo una tabla pisos con el codigo y la descripción, otra de Recibos
>>> >> con
>>> >> el
>>> >> codigo y la descripcion.
>>> >>
>>> >> En otra tabla lineasrecibos tengo los diferentes recibos que paga
>>> >> cada
>>> >> uno
>>> >> de los pisos, de esta forma:
>>> >>
>>> >> Pisos: idpiso int
>>> >> descripcion varchar(30)
>>> >>
>>> >>
>>> >> Recibos: idrecibo int
>>> >> detalle varchar(40)
>>> >> importe decimal(10,2)
>>> >>
>>> >> Lineasrecibos: idpiso int
>>> >> idrecibo int
>>> >>
>>> >> cada piso tiene varias lineas en Linearecibos porque todos pagan mas
>>> >> de
>>> >> un
>>> >> recibo.
>>> >>
>>> >> En ocasiones tengo que realizar un select en el que se detalle
>>> >> informacion
>>> >> con exclusion de uno o mas recibos.
>>> >>
>>> >> yo hago el select asi:
>>> >>
>>> >> select idpiso,descripcion from pisos join (select idpiso from
>>> >> lineasrecibos
>>> >> where idrecibo not in(10)) r on r.idpiso=idpiso.
>>> >>
>>> >> no me funciona porque si un piso paga el recibo 10 y el recibo 12 me
>>> >> sale
>>> >> la
>>> >> linea del recibo 12 y necesito que si esta excluido en el in, aunque
>>> >> tenga
>>> >> otros recibos no salga.
>>> >>
>>> >>
>>> >> Saludos y gracias.
>>> >>
>>> >>
>>> >>
>>> >>
>>> >>
>>>
>>>
>>>
>
>



Respuesta Responder a este mensaje
#12 Jose Antonio
25/05/2005 - 22:42 | Informe spam
Muchas gracias por la lección.

Saludos

"Alejandro Mesa" escribió en el
mensaje news:
Jose Antonio,

Cuando usamos "not exists" en la clausula "where" de una senetencia
"select", sql server no considera la expresion como un argumento de
busqueda
y claro esta que esto puede causar que la consulta sea lenta. Fijate en el
siguiente ejemplo, el plan de ejecucion entre la sentencia que usa "not
exists" y la que usa "exists". En la primera, sql server hace un scan del
indice clustered de la tabla "customers" y en la segunda hace un seek (la
operacion seek sobre un indice es la mas rapida)

use northwind
go

set showplan_text on
go

select
customerid,
companyname,
country
from
dbo.customers as c
where
not exists(
select
*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
oh.customerid = c.customerid
and od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
)

select
customerid,
companyname,
country
from
dbo.customers as c
where
exists(
select
*
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
oh.customerid = c.customerid
and od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
)
go

set showplan_text off
go

Como podemos expresar esta consulta usando "join" y no "not exists"?. Esa
es
una buena pregunta. Posiblemente usando una tabla derivada de los clientes
que han comprado esos productos, y hacer un "left join" entre la tabla
"customers" y la tabla derivada, filtrando el resultado para los clientes
que
no machan.

select
c.customerid,
c.companyname,
c.country
from
dbo.customers as c
left join
(
select
oh.customerid
from
dbo.orders as oh
inner join
dbo.[order details] as od
on oh.orderid = od.orderid
where
od.productid in (20, 21, 22, 23, 24, 25, 26, 27, 28)
) as t
on c.customerid = t.customerid
where
t.customerid is null
go

bueno, ahora hay que comparar los planes de ejecucion de ambas versiones.
en
mi maquina, la que usa "not exists" tiene menor costo respecto al batch.

Veamos como adaptar la sentencia relacionada con tu problema.

select
p.idpiso,
p.descripcion
from
pisos as p
left join
(
select
idpiso
from
lineasrecibos
where
idrecibo in (10, 11, 12)
) as t
on p.idpiso = t.idpiso
where
t.idpiso is null

Ahora prueba que ambas sentencias den el mismo resultado y compara los
planes de ejecucion.


AMB

"Jose Antonio" wrote:

Una pregunta:

Es normal que con la subconsulta el select sea un poco mas lento que con
el
join?

Saludos
"José Antonio" escribió en el
mensaje news:
> Ok. Gracias a todos.
> "Alejandro Mesa" escribió en
> el
> mensaje news:
>> Trata:
>>
>> select idpiso, descripcion
>> from pisos as p
>> where not exists (
>> select *
>> from lineasrecibos as l
>> where l.idpiso = p.idpiso and idrecibo in (10, 11, 12)
>> )
>>
>>
>> AMB
>>
>> "José Antonio" wrote:
>>
>>> Es eso, pero puede ser que quiera excluir los pisos que contengan
>>> mas
>>> de un
>>> recibo.
>>>
>>> Como seria el select si quiero escluir los pisos que contengan los
>>> recibos
>>> 10,.11 y 12?
>>>
>>> Saludos
>>>
>>> "Alejandro Mesa" escribió
>>> en
>>> el
>>> mensaje news:
>>> > Jose Antonio,
>>> >
>>> > Dejame refrasear la pregunta. Quieres excluir los pisos que
>>> > contengan
>>> > determinado recibo?, si es asi, entonces usa:
>>> >
>>> > select idpiso, descripcion
>>> > from pisos as p
>>> > where not exists (
>>> > select *
>>> > from lineasrecibos as l
>>> > where l.idpiso = p.idpiso and idrecibo = 10
>>> > )
>>> >
>>> >
>>> > AMB
>>> >
>>> > "Jose Antonio" wrote:
>>> >
>>> >> Hola grupo.
>>> >>
>>> >> Tengo un problema con una sentencia select que se me resiste y no
>>> >> logro
>>> >> dar
>>> >> con una solucion adecuada:
>>> >>
>>> >> Tengo una tabla pisos con el codigo y la descripción, otra de
>>> >> Recibos
>>> >> con
>>> >> el
>>> >> codigo y la descripcion.
>>> >>
>>> >> En otra tabla lineasrecibos tengo los diferentes recibos que paga
>>> >> cada
>>> >> uno
>>> >> de los pisos, de esta forma:
>>> >>
>>> >> Pisos: idpiso int
>>> >> descripcion varchar(30)
>>> >>
>>> >>
>>> >> Recibos: idrecibo int
>>> >> detalle varchar(40)
>>> >> importe decimal(10,2)
>>> >>
>>> >> Lineasrecibos: idpiso int
>>> >> idrecibo int
>>> >>
>>> >> cada piso tiene varias lineas en Linearecibos porque todos pagan
>>> >> mas
>>> >> de
>>> >> un
>>> >> recibo.
>>> >>
>>> >> En ocasiones tengo que realizar un select en el que se detalle
>>> >> informacion
>>> >> con exclusion de uno o mas recibos.
>>> >>
>>> >> yo hago el select asi:
>>> >>
>>> >> select idpiso,descripcion from pisos join (select idpiso from
>>> >> lineasrecibos
>>> >> where idrecibo not in(10)) r on r.idpiso=idpiso.
>>> >>
>>> >> no me funciona porque si un piso paga el recibo 10 y el recibo 12
>>> >> me
>>> >> sale
>>> >> la
>>> >> linea del recibo 12 y necesito que si esta excluido en el in,
>>> >> aunque
>>> >> tenga
>>> >> otros recibos no salga.
>>> >>
>>> >>
>>> >> Saludos y gracias.
>>> >>
>>> >>
>>> >>
>>> >>
>>> >>
>>>
>>>
>>>
>
>



Respuesta Responder a este mensaje
#13 Don Roque
26/05/2005 - 14:59 | Informe spam
clap clap clap clap
IMPECABLE
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida