2016-10-14 6 views
0

Ich habe 3 Tabellen, products, productscategories und categories.Mysql-Gruppe mit mehreren Spalten mit inneren Verbindungen

Die productscategories ist eine viele zu viele Tabelle mit nur ID-Nummern der anderen beiden Tabellen.

Das Ergebnis ohne die Gruppe sieht wie folgt aus:

id | Url     | Category 
------------------------------------- 
1 | http://example.com/12 | hat 
2 | http://example.com/12 | shoe 
3 | http://example.com/13 | hat 
4 | http://example.com/13 | jacket 
5 | http://example.com/14 | hat 
6 | http://example.com/14 | socks 

Jetzt möchte ich mit der gleichen url jede Zeile auszuschließen, wenn sie eine der gewählten Kategorien, in diesem Fall jacket und shoe.

Das unerwünschte Ergebnis sieht wie folgt aus:

id | Url     | Category 
------------------------------------- 
1 | http://example.com/12 | hat 
3 | http://example.com/13 | hat 
5 | http://example.com/14 | hat 

Da url mit der ID 13 enthält jacket ich es dort nicht wollen. Das Gleiche gilt für url mit 14, die shoe enthält.

Diese accur, weil ich mehrere Kategorien und mehrere URLs haben, die einander nicht bewusst sind.

Die SQL für die oben:

SELECT * FROM products 
JOIN productscategories ON products.id = productscategories.product_id 
JOIN categories ON categories.id = productscategories.category_id 
WHERE categories.slug NOT IN (
    'shoe', 
    'jacket', 
) 
GROUP BY products.image_url 

Das gewünschte Ergebnis:

id | Url     | Category 
------------------------------------- 
5 | http://example.com/14 | hat 

Wie kann ich eine SQL-Abfrage machen, die URL kennt die Kategorie macht, wie oben?

Antwort

1
SELECT * FROM products 
    JOIN productscategories ON products.id = productscategories.product_id 
    JOIN categories ON categories.id = productscategories.category_id 
GROUP BY products.image_url 
HAVING sum(categories.slug IN('shoe','jacket'))=0 

categories.slug IN('shoe','jacket') - Rückkehr 1, wenn Kategorie in Satz oder 0, wenn nicht. sum() - Anzahl der Schuhe/Jacken in der Gruppe zurückgeben. HAVING Filtergruppe mit Schuh/Jacke drin.

+0

Das war eine seltsam aussehende Antwort, aber es funktioniert in meinen Tests und es ist blitzschnell (30-60 Mal schneller als andere Antworten). Keine Fallstricke? Danke! –

+1

@ JensTörnell auf MySQL das funktioniert gut. Auf anderen RDBMS kann Notwendigkeit 'sum (Fall, wenn Kategorien.Slug IN ('Schuh', 'Jacke') dann 1 else 0 Ende)' – Mike

1

Vorschlag 1: WHERE NOT EXISTS

SELECT * FROM products 
JOIN productscategories ON products.id = productscategories.product_id 
JOIN categories ON categories.id = productscategories.category_id 
WHERE NOT EXISTS(
     SELECT 1 
     FROM products p2 
     JOIN productscategories pc2 ON p2.id = pc2.product_id 
     JOIN categories c2 ON c2.id = pc2.category_id 
     WHERE c2.slug IN ('shoe','jacket') 
     AND p2.url = products.url 
) 

Vorschlag 2: OUTER JOIN

SELECT * FROM products 
JOIN productscategories ON products.id = productscategories.product_id 
JOIN categories ON categories.id = productscategories.category_id 
LEFT OUTER JOIN products p2 ON products.url = p2.url 
LEFT OUTER JOIN productscategories pc3 ON p2.id = pc2.product_id 
LEFT OUTER JOIN categories c2 ON c2.id = pc2.category_id AND c2.slug IN ('shoe','jacket') 
WHERE c2.id IS NULL 
+0

Ich habe gerade versucht, sie beide und sie arbeiteten, aber die Ladezeit geht von 1 Sekunde eine halbe Minute zu mögen. :(Sie haben eine 'pc3' in Ihrem Code. Es sollte' pc2' sein. –

0

Versuchen Sie folgendes:

SELECT * FROM (
SELECT * FROM products 
JOIN productscategories ON products.id = productscategories.product_id 
JOIN categories ON categories.id = productscategories.category_id 
) AS A 
LEFT JOIN 
(
SELECT Url FROM products 
JOIN productscategories ON products.id = productscategories.product_id 
JOIN categories ON categories.id = productscategories.category_id 
WHERE Categories.slug IN ('jacket', 'shoe') 
GROUP BY url 
) B ON B.url = A.url 
WHERE B.url IS NULL 
Verwandte Themen