mysql molti-a-uno e di gruppo, dando risultati insoliti
-
12-10-2019 - |
Domanda
im avendo difficoltà con la seguente configurazione piuttosto semplice:
CREATE TABLE IF NOT EXISTS invoices (
id int(11) NOT NULL auto_increment,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS invoices_items (
id int(11) NOT NULL auto_increment,
invoice_id int(11) NOT NULL,
description text NOT NULL,
amount decimal(10,2) NOT NULL default '0.00',
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS invoices_payments (
id int(11) NOT NULL auto_increment,
invoice_id int(11) NOT NULL,
amount decimal(10,2) NOT NULL default '0.00',
PRIMARY KEY (id)
);
alcuni dati:
INSERT INTO invoices (id) VALUES (1);
INSERT INTO invoices_items (id, invoice_id, description, amount) VALUES
(1, 1, 'Item 1', '750.00'),
(2, 1, 'Item 2', '750.00'),
(3, 1, 'Item 3', '50.00'),
(4, 1, 'Item 4', '150.00');
INSERT INTO invoices_payments (id, invoice_id, amount) VALUES
(1, 1, '50.00'),
(2, 1, '1650.00');
e lo sql ottenendo risultati insoliti:
select invoices.id,
ifnull(sum(invoices_payments.amount),0) as payments_total,
ifnull(count(invoices_items.id),0) as item_count
from invoices
left join invoices_items on invoices_items.invoice_id=invoices.id
left join invoices_payments on invoices_payments.invoice_id=invoices.id
group by invoices.id
risultati nell'output (erronea)
id payments_total item_count
1 6800.00 8
Ora, come dimostra vi sia infatti solo quattro righe 'invoice_item', io non capisco perché MySQL non è il raggruppamento in modo corretto.
Modifica
so di poter fare qualcosa di simile:
select x.*, ifnull(sum(invoices_payments.amount),0) as payments_total from (
select invoices.id,
ifnull(count(invoices_items.id),0) as item_count
from invoices
left join invoices_items on invoices_items.invoice_id=invoices.id
group by invoices.id
) as x left join invoices_payments on invoices_payments.invoice_id=x.id
group by x.id
, ma voglio sapere se sto facendo qualcosa di sbagliato nella prima query - i cant immediatamente vedo perché la prima query sta dando risultati non corretti! : (
Soluzione
La logica aderire non è corretto. Nel vostro unirsi, si specifica invoices_items.invoice_id = invoices.id. È inoltre possibile specificare invoices_payments.invoice_id = invoices.id. A causa di transitività, si finisce con:
invoices_items.invoice_id = invoices.id
invoices_payments.invoice_id = invoices.id
invoice_items.invoice_id = invoices_payments.invoice_id
La somma dei pagamenti delle fatture 2 è di $ 1700. Per ogni pagamento della fattura, ci sono 4 invoice_items che soddisfano i rapporti di cui sopra. $ 1700 * 4 = $ 6800.
Per ogni elemento della fattura, ci saranno due pagamenti delle fatture che soddisfano i rapporti di cui sopra. 4 articoli fattura * conteggio 2 = 8.
Altri suggerimenti
Ci sono due tabelle con una relazione molti: una relazione con le fatture. Il valore è il prodotto cartesiano.
I pagamenti deve essere applicato alla fattura, non le voci fattura. Prendi il totale della fattura, poi unire i pagamenti ad esso.
Questo può essere simile a quello che stai cercando:
SELECT
invoice_total.invoice_id,
invoice_total.amount as invoice_amount,
payments_total.amount as total_paid
FROM
(
SELECT
invoice_id,
SUM(amount) as amount
FROM
invoices_items
GROUP BY
invoice_id
) invoice_total
INNER JOIN
(
SELECT
invoice_id,
SUM(amount) as amount
FROM
invoices_payments
GROUP BY
invoice_id
) payments_total
ON invoice_total.invoice_id = payments_total.invoice_id;
modifica:
ah, mi dispiace - vedere il tuo punto ora. Il motivo che stai ricevendo risultati inattesi è che questa query:
SELECT *
FROM invoices
LEFT JOIN invoices_items ON invoices_items.invoice_id = invoices.id
LEFT JOIN invoices_payments ON invoices_payments.invoice_id = invoices.id;
risultati in questo:
id id invoice_id description amount id invoice_id amount
1 1 1 Item 1 750.00 1 1 50.00
1 1 1 Item 1 750.00 2 1 1650.00
1 2 1 Item 2 750.00 1 1 50.00
1 2 1 Item 2 750.00 2 1 1650.00
1 3 1 Item 3 50.00 1 1 50.00
1 3 1 Item 3 50.00 2 1 1650.00
1 4 1 Item 4 150.00 1 1 50.00
1 4 1 Item 4 150.00 2 1 1650.00
Come si può vedere si ottiene ogni record invoices_items
una volta per ogni record invoices_payments
. Si sta andando ad avere per afferrare (cioè gruppo) separatamente.
Si noti che la clausola GROUP BY
nella query iniziale è ridondante.
Ecco quello che vi serve:
SELECT
invoices.id,
payments_total.payments_total,
IFNULL(COUNT(invoices_items.id),0) AS item_count
FROM invoices
LEFT JOIN invoices_items ON invoices.id = invoices_items.invoice_id
LEFT JOIN (
SELECT invoice_id,
IFNULL(SUM(invoices_payments.amount),0) AS payments_total
FROM invoices_payments
GROUP BY invoice_id
) AS payments_total ON invoices.id = payments_total.invoice_id
;