Iterative Abfrage Entwicklung ...
Wenn Sie keinen product
Tisch haben, und nur haben die customer_country_product
Tabelle, können Sie einen Inline-View verwenden, um eine eindeutige Liste von Produkten für jedes Land zu schaffen .
Um Produkte nach Land ...
SELECT ccp.product_id
, ccp.country_id
FROM customer_country_product ccp
GROUP
BY ccp.product_id
, ccp.country_id
Wir diese Abfrage als rowsource verwenden können, indem sie eine Inline-Ansicht zu machen. Umbrechen Sie diese Abfrage in Parens, weisen Sie einen Alias zu und verweisen Sie in der FROM-Klausel einer anderen Abfrage darauf. Um "Paare" von Produkten zu erhalten, können wir die Inline-Ansicht mit sich selbst verbinden (Vermeidung von Paaren desselben Produkts (A_A
) und Vermeidung von doppelten Paaren) (nur eines von A_C
und C_A
zurückgeben).
SELECT a.country_id
, a.product_id AS a_product_id
, b.product_id AS b_product_id
FROM (SELECT ccpa.product_id
, ccpa.country_id
FROM customer_country_product ccpa
GROUP
BY ccpa.product_id
, ccpa.country_id
) a
JOIN (SELECT ccpb.product_id
, ccpb.country_id
FROM customer_country_product ccpb
GROUP
BY ccpb.product_id
, ccpb.country_id
) b
ON b.country_id = a.country_id
AND b.product_id > a.product_id
ORDER
BY a.country_id
, a.product_id
, b.product_id
Das sollte Ihnen alle Produkt "Paare" für jedes Land erhalten. HINWEIS: Dadurch werden Produkte ausgeschlossen, wenn kein Kunde das Produkt besitzt. Wenn wir alle möglichen Produktpaare wollen, für jedes Land, würden wir anders, dass ein wenig schreiben müssen ...
SELECT c.country_id
, a.product_id AS a_product_id
, b.product_id AS b_product_id
FROM (SELECT ccpa.product_id
FROM customer_country_product ccpa
GROUP BY ccpa.product_id
) a
JOIN (SELECT ccpb.product_id
FROM customer_country_product ccpb
GROUP BY ccpb.product_id
) b
ON b.product_id > a.product_id
CROSS
JOIN (SELECT ccpc.country_id
FROM customer_country_product ccpc
GROUP BY ccpc.country_id
) c
ORDER
BY c.country_id
, a.product_id
, b.product_id
Wenn Sie product
und country
Tabellen haben, können Sie die Inline-Ansichten in den Abfragen ersetzen könnte oben mit Verweisen auf diese Tabellen.
Um die "Zählungen" des Kunden zu erhalten, könnten wir entweder korrelierte Unterabfragen in der SELECT-Liste verwenden, oder wir können Join-Operationen und Aggregate in der SELECT-Liste durchführen. (Mit dem beitritt, wenn wir nicht aufpassen, dann ist es ein Potential zu generieren und zählen „Duplikate“.)
Um eine Zählung der verschiedenen Kunden in einem bestimmten Land zu bekommen, die ein bestimmtes Produkt hat
SELECT COUNT(DISTINCT ccp.customer_id) AS cnt_cust
FROM customer_country_product ccp
WHERE ccp.country_id = ?
AND ccp.product_id = ?
Um eine Zählung von verschiedenen Kunden aus einem bestimmten Land zu erhalten, die mindestens eine von zwei bestimmten Produkten
SELECT COUNT(DISTINCT ccp.customer_id) AS cnt_cust_have_either
FROM customer_country_product ccp
WHERE ccp.country_id = ?
AND ccp.product_id IN (? , ?)
hat, um eine Anzahl von Kunden in einem bestimmten Land zu bekommen, die zwei bestimmte Produkte hat:
Da diese Abfragen eine einzelne Zeile mit einer einzelnen Spalte zurückgeben, können wir diese als Ausdrücke in der SELECT-Liste einer anderen Abfrage verwenden. Wir beginnen mit der Abfrage "Produktpaare" und fügen sie zur SELECT-Liste hinzu. Wir ersetzen diese Fragezeichen-Platzhalter mit Verweisen auf Spalten aus der äußeren Abfrage:
SELECT c.country_id
, a.product_id AS a_product_id
, b.product_id AS b_product_id
, (SELECT COUNT(DISTINCT ccp1.customer_id)
FROM customer_country_product ccp1
JOIN customer_country_product ccp2
ON ccp2.country_id = ccp1.country_id
AND ccp2.customer_id = ccp1.customer_id
WHERE ccp1.country_id = c.country_id
AND ccp1.product_id = a.product_id
AND ccp2.product_id = b.product_id
) AS cnt_cust_have_both
, (SELECT COUNT(DISTINCT ccp.customer_id)
FROM customer_country_product ccp
WHERE ccp.country_id = c.country_id
AND ccp.product_id IN (a.product_id,b.product_id)
) AS cnt_cust_have_either
FROM (SELECT ccpa.product_id
FROM customer_country_product ccpa
GROUP BY ccpa.product_id
) a
JOIN (SELECT ccpb.product_id
FROM customer_country_product ccpb
GROUP BY ccpb.product_id
) b
ON b.product_id > a.product_id
CROSS
JOIN (SELECT ccpc.country_id
FROM customer_country_product ccpc
GROUP BY ccpc.country_id
) c
ORDER
BY c.country_id
, a.product_id
, b.product_id
, nun den „Prozentsatz“ berechnen wir brauchen nur eine Divisionsoperation zu tun. Bei MySQL wird eine "Division durch Null" NULL zurückgeben. (Wir würden nicht damit befassen müssen, wenn unsere äußere Abfrage nur die Zeilen zurück, wo wir einen Kunden aus dem Land kennen hat eines der Produkte ... dh das Ergebnis der ersten Abfrage zurückgegeben
SELECT c.country_id
, a.product_id AS a_product_id
, b.product_id AS b_product_id
, (SELECT COUNT(DISTINCT ccp1.customer_id)
FROM customer_country_product ccp1
JOIN customer_country_product ccp2
ON ccp2.country_id = ccp1.country_id
AND ccp2.customer_id = ccp1.customer_id
WHERE ccp1.country_id = c.country_id
AND ccp1.product_id = a.product_id
AND ccp2.product_id = b.product_id
)
/(SELECT COUNT(DISTINCT ccp.customer_id)
FROM customer_country_product ccp
WHERE ccp.country_id = c.country_id
AND ccp.product_id IN (a.product_id,b.product_id)
)
* 100.00 AS percent_cust_have_both
FROM (SELECT ccpa.product_id
FROM customer_country_product ccpa
GROUP BY ccpa.product_id
) a
JOIN (SELECT ccpb.product_id
FROM customer_country_product ccpb
GROUP BY ccpb.product_id
) b
ON b.product_id > a.product_id
CROSS
JOIN (SELECT ccpc.country_id
FROM customer_country_product ccpc
GROUP BY ccpc.country_id
) c
ORDER
BY c.country_id
, a.product_id
, b.product_id
Soweit "aufwärts" zu skalieren, müssen wir für jede nicht-triviale Tabelle geeignete Indizes zur Verfügung haben, insbesondere für die korrelierten Unterabfragen. Diese werden für jede Zeile ausgeführt, die von der äußeren Abfrage zurückgegeben wird.
Diese letzte Abfrage hat das Potenzial, NULL zurückzugeben, wenn im Nenner eine Zählung von Null vorhanden ist.Wir können eine Null ersetzen, indem wir dies während der Division in einen Cond einbetten itional Test
IFNULL(<expr> , 0) * 100.00 AS
(Wahrscheinlich gibt es einen Fehler irgendwo in diesen Abfragen, um eine vermisste paren, eine ungültige Referenz, eine falsche Qualifier, usw. Diese Abfragen werden nicht geprüft. Ich empfehle Ihnen dringend, ein jeder zu testen, und zwar nicht nur, dass die letzte Heimelf.)
Followup
Eine Tabelle zum Testen ...
CREATE TABLE customer_country_product
(customer_id INT
, country_id VARCHAR(2)
, product_id VARCHAR(2)
)
;
INSERT INTO customer_country_product (customer_id, country_id, product_id) VALUES
('1','US','A')
,('1','US','B')
,('2','CA','A')
,('2','CA','C')
,('3','US','A')
,('3','US','C')
,('4','US','B')
,('5','US','A')
;
Schluss Abfrage gibt:
country_id a_product_id b_product_id percent_cust_have_both
---------- ------------ ------------ ----------------------
CA A B 0.000000
CA A C 100.000000
CA B C 0.000000
US A B 25.000000
US A C 33.333333
US B C 0.000000
Es wäre eine triviale Änderung a.product_id
und b.product_id
in einer einzigen Spalte zu verketten. Die zweite und dritte Spalte in der SELECT-Liste könnte durch etwas wie CONCAT(a.product_id,'_',b.product_id) AS a_b
ersetzt werden.
Sollte der US A_C-Wert nicht 33%, nicht 25% betragen? Drei Kunden (1, 3, 5) kauften entweder A oder C, und einer von ihnen (3) kaufte beide. – APH
@APH du bist richtig. Es sollte 33% sein – Black