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

#6 Ricardo Passians
05/11/2007 - 12:11 | Informe spam

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,



Sujeto a confirmación (pues no puedo probarlo ahora) pero creo que el SUM()
no daría NULL en ese caso que dices, donde algunos valores fruto del LEFT
JOIN no existan. Si acaso puede dar una advertencia en algunos casos, si
mal no recuerdo ahora pero ciertamente creo que ignora los valores null al
sumar. Claro que si lo pone como sugieres (sum(isnull(valor,0)) el código es
mas seguro y se evitan las posibles advertencias.

Por otro lado, uno de los casos donde sí envolver el SUM con un ISNULL es
util es cuando no hay un un Group By.

Ejemplo para el caso que da Alexis:

select SUM(valor) from pagos where numcompraF

Si la compra # 46 no tiene ningun registro de pago, pues el resultado sería
un registro con un NULL!.
Por tanto aqui sería práctico hacerlo así:

select ISNULL(SUM(valor),0) from pagos where numcompraF

Sin embargo si hubiese algún group by, no es necesario el ISNULL
Si Alexis en vez de un LEFT JOIN, habria usado subconsultas, de esa forma
entonces sí habría requerido el ISNULL envolviendo al SUM:

select compras.numcompra, comprado=compras.valor,
pagado=(select ISNULL(SUM(pagos.valor),0) from pagos
where pagos.numcompra=compras.nomcompra)
from compras

Es de asumirse tambien que pagos.valor no contendrá NULLs por sí mismo.


Saludos

Ricardo Passians
Respuesta Responder a este mensaje
#7 Carlos M. Calvelo
05/11/2007 - 12:29 | Informe spam
On 5 nov, 03:02, 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 ) )"




Hola,

Mira este ejemplo:
-
create table Tab (
TabId int not null primary key,
N int
)

insert into Tab (TabId,N) values (1,1)
insert into Tab (TabId,N) values (2,2)
insert into Tab (TabId,N) values (3,null)

select sum(N) from Tab

select sum(N) from Tab where TabId > 100

select sum(N) from tab where TabId = 3

drop table Tab


El primer select devuelve 3, pero debería ser null.
(4 + <algo_desconocido> debe ser <algo_desconocido>)

El segundo select devuelve null, pero debería ser 0.
(La suma de cero sumandos debe ser 0)

El tercer select devuelve null, como debe ser.


Si queremos interpretar el null como 0 (que no lo es!),
entonces se puede deducir de estos ejemplos que el
sum(isnull(N,0)) nunca tiene sentido.
En cuanto al isnull(sum(N),0) tenemos dos casos:
- Sumamos una selección con 0 registros:
Entonces isnull(sum(N),0) corrige el error de SQL.
- Sumamos una selección mas de 0 registros y todos
ellos tienen null en el campo a sumar:
Entonces isnull(sum(N),0) interpreta el resultado
null (que es correcto) como 0.

Conclusión: SQL no sabe sumar. :-)

Saludos,
Carlos
Respuesta Responder a este mensaje
#8 jeastman
05/11/2007 - 14:56 | Informe spam
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 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


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.

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


Lo que dice el amigo Ricardo es cierto en el ejemplo que pasé
inicialmente, si se cumple la condición entre las dos tablas retorna un
valor, pero, en caso contrario se retornará es un NULL y no un cero (0).

Saludos.


Ricardo Passians escribió:
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,



Sujeto a confirmación (pues no puedo probarlo ahora) pero creo que el SUM()
no daría NULL en ese caso que dices, donde algunos valores fruto del LEFT
JOIN no existan. Si acaso puede dar una advertencia en algunos casos, si
mal no recuerdo ahora pero ciertamente creo que ignora los valores null al
sumar. Claro que si lo pone como sugieres (sum(isnull(valor,0)) el código es
mas seguro y se evitan las posibles advertencias.

Por otro lado, uno de los casos donde sí envolver el SUM con un ISNULL es
util es cuando no hay un un Group By.

Ejemplo para el caso que da Alexis:

select SUM(valor) from pagos where numcompraF

Si la compra # 46 no tiene ningun registro de pago, pues el resultado sería
un registro con un NULL!.
Por tanto aqui sería práctico hacerlo así:

select ISNULL(SUM(valor),0) from pagos where numcompraF

Sin embargo si hubiese algún group by, no es necesario el ISNULL
Si Alexis en vez de un LEFT JOIN, habria usado subconsultas, de esa forma
entonces sí habría requerido el ISNULL envolviendo al SUM:

select compras.numcompra, comprado=compras.valor,
pagado=(select ISNULL(SUM(pagos.valor),0) from pagos
where pagos.numcompra=compras.nomcompra)
from compras

Es de asumirse tambien que pagos.valor no contendrá NULLs por sí mismo.


Saludos

Ricardo Passians


Respuesta Responder a este mensaje
#9 jeastman
05/11/2007 - 15:05 | Informe spam
Hola Carlos.

Cuando creo tablas todos los campos son NOT NULL, por ello nunca me ha
pasado lo que demuestras en la consulta 1 y 2, acabo de probarlo y cual
fue mi sopresa!!!, el resultado no fue el esperado (por mi claro).

Gracias a ese comentario acabo de agregar algo más a mi conocimientos.

Saludos.

Carlos M. Calvelo escribió:
On 5 nov, 03:02, 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 ) )"




Hola,

Mira este ejemplo:
-
create table Tab (
TabId int not null primary key,
N int
)

insert into Tab (TabId,N) values (1,1)
insert into Tab (TabId,N) values (2,2)
insert into Tab (TabId,N) values (3,null)

select sum(N) from Tab

select sum(N) from Tab where TabId > 100

select sum(N) from tab where TabId = 3

drop table Tab


El primer select devuelve 3, pero debería ser null.
(4 + <algo_desconocido> debe ser <algo_desconocido>)

El segundo select devuelve null, pero debería ser 0.
(La suma de cero sumandos debe ser 0)

El tercer select devuelve null, como debe ser.


Si queremos interpretar el null como 0 (que no lo es!),
entonces se puede deducir de estos ejemplos que el
sum(isnull(N,0)) nunca tiene sentido.
En cuanto al isnull(sum(N),0) tenemos dos casos:
- Sumamos una selección con 0 registros:
Entonces isnull(sum(N),0) corrige el error de SQL.
- Sumamos una selección mas de 0 registros y todos
ellos tienen null en el campo a sumar:
Entonces isnull(sum(N),0) interpreta el resultado
null (que es correcto) como 0.

Conclusión: SQL no sabe sumar. :-)

Saludos,
Carlos

Respuesta Responder a este mensaje
#10 Alejandro Mesa
05/11/2007 - 15:44 | Informe spam
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
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida