Duda con Isnull en SUM

04/11/2007 - 18:06 por Alexis | Informe spam
Solicito su ayuda para esto:

Tengo dos tablas
a) registros de compras
compras (numcompra, valor, fecha)

b)registros de pagos de esas compras
pagos (numcompra, numpago, valor)

Es una relacion opcional de 1 a N por Numcompra y quiero obtener los
balances de cada compra:

Numcompra, Comprado, Pagado

Tengo el siguiente select:

select numcompra, comprado=compras.valor, pagado=sum(pagos.valor)
from compras
left join pagos on compras.numcompra=pagos.numcompra
group by numcompra,compras.valor

Dado que es un Left Join, la pregunta es como debo usar ISNULL para que la
columna "Pagado" me de Cero cuando la compra no tenga ningun pago:

asi: ISNULL(sum(pagos.valor),0)
o asi: sum( ISNULL(pagos.valor,0) )
o asi: ISNULL(sum( ISNULL(pagos.valor,0) ), 0)
?


Gracias

Preguntas similare

Leer las respuestas

#11 jeastman
05/11/2007 - 18:58 | Informe spam
Hola Alejandro.

Definitivamente.

Creo que generalicé el asunto del manejo de los null y no tomé en cuenta
algunos detalles.

Gracias por tus comentarios, de hecho me enteré de algo que no sabía.

Saludos.

Alejandro Mesa escribió:
Hola Jorge,

Si haces lo mensionado más arriba "isnull( sum( ... ), 0 )" existe la
posibilidad que alguno de los valores que le pasas a sun sea nulo por lo
que todo el resultado de sum será null, por ello es que se debe hacer
así "sum( isnull( ..., 0 ) )"



Las funciones de grupo no toman en cuenta valores NULL. Eso lo puedes ver en
la siguiente sentencia:

select SUM(CAST(NULL AS INT))
GO

Warning: Null value is eliminated by an aggregate or other SET operation.

(1 row(s) affected)

Cuando se usa una funcion de grupo, la sentencia debe devolver algo, pero si
no hay nada que agregar, entonces devuelve NULL.

SELECT SUM(c1)
FROM (SELECT CAST(NULL AS INT) WHERE 0 = 1) AS t1(c1)
GO

USE Northwind
GO

SELECT SUM(Quantity)
FROM dbo.[Order Details]
WHERE 0 = 1
GO

Asi que respondiendo la pregunta de Alexis, en tu caso podemos usar ambos
procedimientos, ISNULL(SUM(pagos.valor)) o SUM(ISNULL(pagos.valor)), dado que
el operador de union que usas, creara una fila de pago fictisia para las
compras que no tienen pago asociado.

SELECT
compras.numcompra,
SUM(compras.valor) AS comprado,
SUM(pagos.valor) AS pagado
FROM
(
SELECT 1 AS numcompra, 4 AS [valor]
UNION ALL
SELECT 2 AS numcompra, 17 AS [valor]
) AS compras
LEFT JOIN
(
SELECT 1 AS numcompra, 4 AS [valor]
) AS pagos
ON compras.numcompra = pagos.numcompra
GROUP BY
compras.numcompra

SELECT
compras.numcompra,
SUM(compras.valor) AS comprado,
ISNULL(SUM(pagos.valor), 0) AS pagado
FROM
(
SELECT 1 AS numcompra, 4 AS [valor]
UNION ALL
SELECT 2 AS numcompra, 17 AS [valor]
) AS compras
LEFT JOIN
(
SELECT 1 AS numcompra, 4 AS [valor]
) AS pagos
ON compras.numcompra = pagos.numcompra
GROUP BY
compras.numcompra

SELECT
compras.numcompra,
SUM(compras.valor) AS comprado,
SUM(ISNULL(pagos.valor, 0)) AS pagado
FROM
(
SELECT 1 AS numcompra, 4 AS [valor]
UNION ALL
SELECT 2 AS numcompra, 17 AS [valor]
) AS compras
LEFT JOIN
(
SELECT 1 AS numcompra, 4 AS [valor]
) AS pagos
ON compras.numcompra = pagos.numcompra
GROUP BY
compras.numcompra


AMB

"jeastman" wrote:

Hola Alexis.

Estaba respondiendo a tu pregunta, pero creo que no supe explicarme.

Yo hasta ahora nunca he visto la necesidad de envolver un sum con un
isnull "isnull( sum( ... ), 0 ).

Por lo contrario y es lo que te explico en el mensaje anterior.

Si haces lo mensionado más arriba "isnull( sum( ... ), 0 )" existe la
posibilidad que alguno de los valores que le pasas a sun sea nulo por lo
que todo el resultado de sum será null, por ello es que se debe hacer
así "sum( isnull( ..., 0 ) )"



Saludos.

Alexis escribió:
Si observas con atención mi ejemplo es un poco diferente al tuyo.

mi ejemplo

select sum( isnull( pagos.valor, 0 ) )

el tuyo

select isnull( sum( pagos.valor ), 0 )



Claro, tu respuesta la entendi bien como valida. Mi pregunta nueva es otra
que no tiene que ver con dicha respuesta.

De todos modos gracias de nuevo.



Respuesta Responder a este mensaje
#12 Carlos M. Calvelo
05/11/2007 - 19:55 | Informe spam
Hola jeastman,

On 5 nov, 14:56, jeastman wrote:
Hola Ricardo.

Es cierto, en un left join el sum no tiene problema hasta cierto punto,
me explico.

Si un renglon en tablaIzquierda tiene registros en tablaDerecha, no
retornará valor null para ese valor, caso contrario cuando no hay
conicidencias entre las dos tablas, veamos un ejemplo:

select i.codProducto,
sum( @impuesto * d.monto )
from inventario i left join detalleFacturas d on
d.numFactura = i.numFactura

En éste caso, dode necesitamos obtener la suma de todos los productos
aplicando una tasa, para los casos en que coincidan registros a ambos
lados del left se retornará un resultado, pero para aquellos casos donde
la tabla derrecha no tenga registros hay si hay un problema, d.monto
será null, la multiplicación dará null y el resultado de la suma dará
null



Esto último ("el resultado de la suma dará null") no es cierto.
Mira el primer ejemplo del otro post mio.

y en esos casos uno lo que quieres un un valor numérico pero no un
null.

Yo prefiero hacerlo de la forma siguiente para evitarme ese problema, y
por que el isnull dentro del sum y no alrevez, por que solo envuelvo a
quien puede tener un valor null.

select i.codProducto,
sum( @impuesto * isnull( d.monto, 0 ) )
from inventario i left join detalleFacturas d on
d.numFactura = i.numFactura




Lo cual no es necesario.
isnull(sum(@impuesto * d.monto), 0) dará el mismo resultado.
Y para el que esté preocupado con la eficiencia, se ahorará
muchos isnull()'s

Ahora en otro caso:

select i.codProducto,
sum( d.cantidad ) as cantidadFacturado,
sum( r.cantidad ) as cantidadDevuelto,
sum( d.cantidad - r.cantidad ) as cantidadEfectivaVentas
from inventario i inner join detalleFactura d on
d.codProducto = i.codProducto
left join (select codProducto,
sum( cantidad ) as cantidad
from reversoVenta r
group by codProducto ) as r on
r.codProducto = i.codProducto
group by i.codProducto

Ésto es un ejemplo simplificado

En éste caso, si para algún producto no hay devoluciones en venta tanto
cantidadDevuelto como cantidadEfectivaVenta retornará null.

Para ello es recomendable hacerlo de la forma siguiente:

select i.codProducto,
sum( d.cantidad ) as cantidadFacturado,
sum( isnull( r.cantidad, 0 ) ) as cantidadDevuelto,
sum( d.cantidad - isnull( r.cantidad, 0 ) ) as cantidadEfectivaVentas
from inventario i inner join detalleFactura d on
d.codProducto = i.codProducto
left join (select codProducto,
sum( cantidad ) as cantidad
from reversoVenta r
group by codProducto ) as r on
r.codProducto = i.codProducto
group by i.codProducto

Ahora, observemos que el isnull envuelve a la columna que pertenece a la
subconsulta que está a la parte derecha del left join y no del sum,
¿porqué, si se envuelve el sum y uno de los valores de r.cantidad es
null el sum será null y el resultado será cero (0), cual en realidad (en
el caso de cantidadEfectivaVentas) deve retornar el valor de la suma de
d.cantidad.



select i.codProducto,
sum( d.cantidad ) as cantidadFacturado,
isnull(sum(r.cantidad), 0) as cantidadDevuelto,
sum(d.cantidad) - isnull(sum(r.cantidad), 0) as
cantidadEfectivaVentas
.



No se si logro explicarme, pero se puede probar lo que se muestra, si
existe alguna duda por favor indicarlo.




Pensaba yo que con los ejemplos cortos que había dado estaba claro.
No va a cambiar el comportamiento del sum con nulos por dar
ejemplos mucho mas complicados. :)

Saludos,
Carlos
Respuesta Responder a este mensaje
#13 jeastman
06/11/2007 - 05:12 | Informe spam
Compañeros, un saludos.

De verdad lamento el hecho de que no me he podido explicar claramente,
estoy deacuerdo con lo que ustedes dicen y de hecho he podido ver un par
de cosas que no sabía y agradesco eso.

Aqui incluyo un fragmento de código de algo que me pasó una vez, pero
como no he logrado explicarme aqui les pongo el emjemplo, por favor
ejecutenlo.

Nuevamente gracias por su paciencia y en especial por los conocimientos
expuesto, que como ya dije antes, también me ha ayudado a mi.

Saludos para todos

begin transaction


create table inventario (
codProducto int not null
)

create table facturaDetalle (
numFactura int not null,
codProducto int not null,
cantidad int not null,
monto money not null
)

create table devolucionVenta (
codProducto int not null,
cantidad int not null
)

insert into inventario values ( 1 )
insert into inventario values ( 2 )
insert into inventario values ( 3 )
insert into inventario values ( 4 )

insert into facturaDetalle values ( 1, 1, 2, 100 )
insert into facturaDetalle values ( 2, 2, 5, 200 )
insert into facturaDetalle values ( 3, 3, 3, 300 )
insert into facturaDetalle values ( 4, 2, 7, 900 )
insert into facturaDetalle values ( 5, 3, 2, 200 )
insert into facturaDetalle values ( 6, 1, 9, 700 )
insert into facturaDetalle values ( 7, 1, 5, 500 )


insert into devolucionVenta values ( 1, 2 )
insert into devolucionVenta values ( 1, 1 )
insert into devolucionVenta values ( 2, 1 )


select i.codProducto,
sum( f.cantidad ) as cantidad,
sum( f.cantidad * f.monto ) as monto
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad - d.cantidad ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad - isnull( d.cantidad, 0 ) ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
isnull( sum( f.cantidad - d.cantidad ), 0 ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

rollback transaction

Obersevese con atención el resultado de las tres últimas consultas,
adicional, en mi caso, no me sirve que las consultas me retornen valores
NULL.

Alexis escribió:
Solicito su ayuda para esto:

Tengo dos tablas
a) registros de compras
compras (numcompra, valor, fecha)

b)registros de pagos de esas compras
pagos (numcompra, numpago, valor)

Es una relacion opcional de 1 a N por Numcompra y quiero obtener los
balances de cada compra:

Numcompra, Comprado, Pagado

Tengo el siguiente select:

select numcompra, comprado=compras.valor, pagado=sum(pagos.valor)
from compras
left join pagos on compras.numcompra=pagos.numcompra
group by numcompra,compras.valor

Dado que es un Left Join, la pregunta es como debo usar ISNULL para que la
columna "Pagado" me de Cero cuando la compra no tenga ningun pago:

asi: ISNULL(sum(pagos.valor),0)
o asi: sum( ISNULL(pagos.valor,0) )
o asi: ISNULL(sum( ISNULL(pagos.valor,0) ), 0)
?


Gracias


Respuesta Responder a este mensaje
#14 jeastman
06/11/2007 - 05:24 | Informe spam
Disculpen, se me fue un error en el primer ejemplo.

Aqui está nuevamente.

begin transaction


create table inventario (
codProducto int not null
)

create table facturaDetalle (
numFactura int not null,
codProducto int not null,
cantidad int not null,
monto money not null
)

create table devolucionVenta (
codProducto int not null,
cantidad int not null
)

insert into inventario values ( 1 )
insert into inventario values ( 2 )
insert into inventario values ( 3 )
insert into inventario values ( 4 )

insert into facturaDetalle values ( 1, 1, 2, 100 )
insert into facturaDetalle values ( 2, 2, 5, 200 )
insert into facturaDetalle values ( 3, 3, 3, 300 )
insert into facturaDetalle values ( 4, 2, 7, 900 )
insert into facturaDetalle values ( 5, 3, 2, 200 )
insert into facturaDetalle values ( 6, 1, 9, 700 )
insert into facturaDetalle values ( 7, 1, 5, 500 )


insert into devolucionVenta values ( 1, 2 )
insert into devolucionVenta values ( 1, 1 )
insert into devolucionVenta values ( 2, 1 )


select i.codProducto,
sum( f.cantidad ) as cantidad,
sum( f.cantidad * f.monto ) as monto
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
group by i.codProducto
order by 1

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad ) - d.cantidad as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto,
d.cantidad
order by 1

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad ) - isnull( d.cantidad, 0 ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto,
d.cantidad
order by 1

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
isnull( sum( f.cantidad ) - d.cantidad, 0 ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto,
d.cantidad
order by 1

rollback transaction

jeastman escribió:
Compañeros, un saludos.

De verdad lamento el hecho de que no me he podido explicar claramente,
estoy deacuerdo con lo que ustedes dicen y de hecho he podido ver un par
de cosas que no sabía y agradesco eso.

Aqui incluyo un fragmento de código de algo que me pasó una vez, pero
como no he logrado explicarme aqui les pongo el emjemplo, por favor
ejecutenlo.

Nuevamente gracias por su paciencia y en especial por los conocimientos
expuesto, que como ya dije antes, también me ha ayudado a mi.

Saludos para todos

begin transaction


create table inventario (
codProducto int not null
)

create table facturaDetalle (
numFactura int not null,
codProducto int not null,
cantidad int not null,
monto money not null
)

create table devolucionVenta (
codProducto int not null,
cantidad int not null
)

insert into inventario values ( 1 )
insert into inventario values ( 2 )
insert into inventario values ( 3 )
insert into inventario values ( 4 )

insert into facturaDetalle values ( 1, 1, 2, 100 )
insert into facturaDetalle values ( 2, 2, 5, 200 )
insert into facturaDetalle values ( 3, 3, 3, 300 )
insert into facturaDetalle values ( 4, 2, 7, 900 )
insert into facturaDetalle values ( 5, 3, 2, 200 )
insert into facturaDetalle values ( 6, 1, 9, 700 )
insert into facturaDetalle values ( 7, 1, 5, 500 )


insert into devolucionVenta values ( 1, 2 )
insert into devolucionVenta values ( 1, 1 )
insert into devolucionVenta values ( 2, 1 )


select i.codProducto,
sum( f.cantidad ) as cantidad,
sum( f.cantidad * f.monto ) as monto
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad - d.cantidad ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
sum( f.cantidad - isnull( d.cantidad, 0 ) ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

select i.codProducto,
sum( f.cantidad ) as cantidadFacturado,
isnull( sum( f.cantidad - d.cantidad ), 0 ) as ventaEfectiva
from inventario i left join facturaDetalle f on
f.codProducto = i.codProducto
left join ( select
d.codProducto,
sum( d.cantidad ) as cantidad
from devolucionVenta d
group by d.codProducto ) as d on
d.codProducto = i.codProducto
group by i.codProducto

rollback transaction

Obersevese con atención el resultado de las tres últimas consultas,
adicional, en mi caso, no me sirve que las consultas me retornen valores
NULL.

Alexis escribió:
Solicito su ayuda para esto:

Tengo dos tablas
a) registros de compras
compras (numcompra, valor, fecha)

b)registros de pagos de esas compras
pagos (numcompra, numpago, valor)

Es una relacion opcional de 1 a N por Numcompra y quiero obtener los
balances de cada compra:

Numcompra, Comprado, Pagado

Tengo el siguiente select:

select numcompra, comprado=compras.valor, pagado=sum(pagos.valor)
from compras
left join pagos on compras.numcompra=pagos.numcompra
group by numcompra,compras.valor

Dado que es un Left Join, la pregunta es como debo usar ISNULL para
que la columna "Pagado" me de Cero cuando la compra no tenga ningun pago:

asi: ISNULL(sum(pagos.valor),0)
o asi: sum( ISNULL(pagos.valor,0) )
o asi: ISNULL(sum( ISNULL(pagos.valor,0) ), 0)
?


Gracias

Respuesta Responder a este mensaje
#15 Carlos M. Calvelo
06/11/2007 - 09:16 | Informe spam
Hola jeastman,

On 6 nov, 05:12, jeastman wrote:
Compañeros, un saludos.

De verdad lamento el hecho de que no me he podido explicar claramente,
estoy deacuerdo con lo que ustedes dicen ...



No pasa nada. Facilmente he podido yo haber metido la pata.
Ahora no tengo tiempo, pero ya miraré tu ejemplo mas detenidamente.

Saludos,
Carlos
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida