2009-08-06 15 views
6

Heredé el siguiente diseño de base de datos. Las tablas son:SQL JOIN, GROUP BY en tres tablas para obtener totales

customers 
--------- 
customerid 
customernumber 

invoices 
-------- 
invoiceid 
amount 

invoicepayments 
--------------- 
invoicepaymentid 
invoiceid 
paymentid 

payments 
-------- 
paymentid 
customerid 
amount 

Mi consulta tiene que volver InvoiceID, el importe de la factura (en la tabla de facturas), y la cantidad adeudada (importe de la factura menos los pagos que se han hecho hacia la factura) para un CUSTOMERNUMBER dado. Un cliente puede tener múltiples facturas.

La siguiente consulta me da, registros duplicados cuando los pagos se realizan múltiples a una factura:

SELECT i.invoiceid, i.amount, i.amount - p.amount AS amountdue 
FROM invoices i 
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid 
LEFT JOIN payments p ON ip.paymentid = p.paymentid 
LEFT JOIN customers c ON p.customerid = c.customerid 
WHERE c.customernumber = '100' 

¿Cómo puedo solucionar esto?

+0

¿cuántas filas de pagos de facturas pueden existir para una factura? ¿cuántos pagos pueden existir para cada paymentid? –

Respuesta

10

No estoy seguro de lo que era pero esto podría ser lo que busca:

SELECT i.invoiceid, sum(case when i.amount is not null then i.amount else 0 end), sum(case when i.amount is not null then i.amount else 0 end) - sum(case when p.amount is not null then p.amount else 0 end) AS amountdue 
FROM invoices i 
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid 
LEFT JOIN payments p ON ip.paymentid = p.paymentid 
LEFT JOIN customers c ON p.customerid = c.customerid 
WHERE c.customernumber = '100' 
GROUP BY i.invoiceid 

Esto sería conseguir que las cantidades sumas de dinero en caso de que haya varias filas de pago de cada factura

+1

Probablemente debe envolver las columnas 'cantidad' en' coalesce' o 'isnull'; con MS-SQL, cualquier valor NULL, p. desde el 'left join's causará que todo se evalúe a NULL. Sé que algunos dialectos de SQL permiten NULL == 0, pero eso lleva a una guerra religiosa, así que ... – Adrien

+0

Tienes razón, agregué cláusulas de "caso" ya que no estoy seguro de lo que SQL está utilizando. ¡Gracias! –

+0

Personalmente, no sumaría las cantidades de la factura, suponiendo que invoiceid es una clave principal y que el importe en la tabla de facturas está restringido a ser NOT NULL, y en su lugar agregue i.amount a la cláusula GROUP BY. –

2

Primera de todos, ¿no debería haber un Id. de cliente en la tabla Facturas? Tal como está, no puede realizar esta consulta para las facturas que aún no tienen pagos. Si no hay pagos en una factura, esa factura ni siquiera se mostrará en la salida de la consulta, aunque sea una combinación externa ...

Además, cuando un cliente realiza un pago, ¿cómo sabe qué Factura para adjuntarlo Si la única forma es mediante InvoiceId en el talón que se entrega con el pago, entonces está (tal vez inapropiadamente) asociando facturas con el cliente que las pagó, en lugar de con el cliente que las ordenó ... (Algunas veces una factura puede ser pagada por alguien que no sea el cliente que ordenó los servicios)

+0

Estos son realmente buenos puntos; aunque diría que su última declaración es una regla comercial que puede o no ser cierta en la compañía del póster. En general, el diseño es desordenado, y tal como está, no tiene sentido utilizar uniones externas, ya que el predicado requiere que se devuelva una fila de los clientes –

4

¡Muchas gracias por las respuestas!

Saggi Malachi, esa consulta lamenta el monto de la factura en los casos en que hay más de un pago. Supongamos que hay dos pagos a una factura de $ 18 y $ 12. Así que en lugar de terminar con un resultado que parece:

1 39.00 9.00 

Usted va a terminar con:

1 78.00 48.00 

Charles Bretana, en el curso de mi consulta recorte hasta el más simple posible consulta I (estúpidamente) omitió una tabla adicional, customerinvoices, que proporciona un enlace entre los clientes y las facturas. Esto se puede usar para ver las facturas para las cuales los pagos no se han realizado.

Después de mucha lucha, creo que la siguiente consulta devuelve lo que necesito para:

SELECT DISTINCT i.invoiceid, i.amount, ISNULL(i.amount - p.amount, i.amount) AS amountdue 
FROM invoices i 
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid 
LEFT JOIN customerinvoices ci ON i.invoiceid = ci.invoiceid 
LEFT JOIN (
    SELECT invoiceid, SUM(p.amount) amount 
    FROM invoicepayments ip 
    LEFT JOIN payments p ON ip.paymentid = p.paymentid 
    GROUP BY ip.invoiceid 
) p 
ON p.invoiceid = ip.invoiceid 
LEFT JOIN payments p2 ON ip.paymentid = p2.paymentid 
LEFT JOIN customers c ON ci.customerid = c.customerid 
WHERE c.customernumber='100' 

¿Quieres que concurren chicos?

+0

sí, que se ve bien. – RiddlerDev

2

Tengo un consejo para aquellos que desean obtener varios valores agregados de la misma tabla.

Digamos que tengo una tabla con los usuarios y una tabla con los puntos que adquieren los usuarios. Entonces la conexión entre ellos es 1: N (un usuario, muchos registros de puntos).

Ahora en la tabla 'puntos' también almaceno la información acerca de para qué obtuvo el usuario los puntos (iniciar sesión, hacer clic en un banner, etc.).Y quiero enumerar todos los usuarios ordenados por SUM(points) Y luego por SUM(points WHERE type = x). Es decir ordenado por todos los puntos que tiene el usuario y luego por puntos que el usuario obtuvo para una acción específica (por ej., Inicio de sesión).

El SQL sería:

SELECT SUM(points.points) AS points_all, SUM(points.points * (points.type = 7)) AS points_login 
FROM user 
LEFT JOIN points ON user.id = points.user_id 
GROUP BY user.id 

La belleza de esto es en el SUM(points.points * (points.type = 7)), donde el paréntesis interior se evalúa como 0 o 1 multiplicando así el valor puntos dados por 0 o 1, dependiendo de wheteher es igual al tipo de puntos que queremos.