2010-02-15 19 views
5

Ich bin ziemlich ein Anfänger und ich habe zwei Tabellen: "Produkt" und "Produktattribute".Auswählen gegen Teilmengen einer Liste in MySQL

Hier einige imaginären Daten

Produkte Tabelle (die tatsächlichen Sachen mehr Tabellen beinhalten):

product_id | product_name     
10   | aaa       
11   | bbb 
12   | ccc 

Attribute Table:

attribute_id | product_id 
     21  | 10   
     23  | 10   
     24  | 10   
     21  | 11   
     24  | 11   
     21  | 12   
     25  | 12   

Wo jedes Produkt mehr als ein mögliche Attribut . Ich habe eine Liste von Attribut-IDs wie (21,10,25) und ich muss alle Produkte auswählen, deren Attribute eine Teilmenge dieser Liste sind.

Ist es möglich, dies in einer Abfrage zu tun?

Wenn ich Filter für (21,24) gewünscht wird nur ausgegeben Produkt 11 (bbb)

Wenn ich Filter für (21,23,24) gewünschte Ausgangssignal wird an das Rückprodukte 10 und 11

zurückzukehren

Wenn ich filter für (21) gewünschte Ausgabe ist, keine zurückzugeben (weil alle Produkte mindestens ein anderes Attribut haben).

Antwort

5

Wenn Sie behaupten, dass Sie einen Filter in einer Tabelle ist:

select * 
from product p 
where not exists (
    select 1 
    from attributes a 
    where a.product_id = p.product_id 
    and not exists(
     select 1 
     from filter f 
     where f.id_attribute = a.id_attribute)) 

Wenn es in einer konstruierten Abfrage:

select * 
from product p 
where not exists (
    select 1 
    from attributes a 
    where a.product_id = p.product_id 
    and attribute_id not in (<list>)) 

Das ist von der Spitze meines Kopfes, so kann Tippfehler haben.

+1

ja, das zweite funktioniert, danke –

+0

Es funktioniert danke :) – Ashu

1

Vorausgesetzt, dass Ihr Produkttabelle Produkt und die ID-Spalte in der Tabelle aufgerufen wird, wird nur Id genannt:

SELECT * from Product p where p.Id IN 
    (Select id_product from ProductAttributes where id_attribute in (21, 23, 24)) 
+0

ja, aber das würde auch Produkte mit einem Attribut in der Liste und die andere nicht in der Liste auswählen. Ich habe es schon so gemacht.Ich brauche sie, um alle Attribute in der Liste zu haben (wie ich sagte), also jede mögliche Reihe von der Attributtabelle mit mit dieser product_id –

1
select 
    P.id, 
    P.name, 
    count(P.id) as matched_attr_count, 
    count(PA.a_id) as total_attr_count 
from 
    product_attributes PA 
    left join product P on P.id = PA.p_id and PA.a_id in (21,23,24) 
group by 
    PA.p_id 
having 
    matched_attr_count = total_attr_count; 
+0

diese Lösung scheint auch zu funktionieren, außer es gibt mehr Reihen pro Produkt zurück, also würde es eine Gruppe durch P. profitieren id_product in it edit: nein, es funktioniert nicht .. das gleiche Problem, es filtert nicht alle Attribute eines Produkts, es ist genug für eine von ihnen in der Liste zu sein –

+0

ja, aber es gibt auch die andere Problem, dass es nicht alle Attribute filtert –

+0

Ich habe dich zuerst missverstanden. Sieht aus wie jetzt behoben? – Qwerty

-1

lassen Sie mich einfach imaginäre Daten schreiben (das eigentliche Material beinhaltet mehr Tabellen)

Tabelle Produkte

product_id | product_name     
10   | aaa       
11  | bbb 

Tisch product_attribute

attribute_id | product_id <br> 
21  | 10   
23  | 10   
24  | 10   
21  | 11   
24  | 11 

ich will, dass:

  • , wenn ich für (21,24) filtern, um nur Produkt zurückgegeben werden 11 (bbb)
  • , wenn ich für (21,23,24) filtern beide zurückgegeben werden Produkte
  • wenn ich filtere für (21) nur zurückgegeben werden keine (weil keine pro Kanal hat nur das Attribut)
+0

dieses Zeug ist in Prestashop, wenn Sie ein Modul nach Attributen filtern müssen , aber komplexere Tabellen und Beziehungen –

+1

Ich würde vorschlagen, dass Sie die Frage bearbeiten und diese zur Frage hinzufügen. –

+1

Diese Art von Informationen sollte in Ihrer ursprünglichen Frage enthalten sein. Sie können Ihre Frage bearbeiten, wenn Sie später weitere Informationen hinzufügen möchten. Ich habe deine Frage für dich bearbeitet. –

1

Dies sollte nur die IDs zurück, wo alle Attribute für jede ID vollständig innerhalb der Liste enthalten sind:

select attribute_match.id_product from 
(select id_product, count(*) c from attributes 
    where id_attribute in (21, 10, 25) 
    group by id_product) attribute_match, 
(select id_product, count(*) c_count from attributes 
    group by id_product) attribute_total 
where attribute_match.id_product = attribute_total.id_product 
     and attribute_match.c = attribute_total.c 
+0

dies funktioniert nicht im Fall (21,23,24) (wählt nur 1 Produkt) –

+0

Ich denke, die überarbeitete Abfrage sollte funktionieren - die erste innere Auswahl sollte 10,3 11,2 generieren und die zweite innere Auswahl sollte 10 generieren , 3 11,2 und so sollte die äußere Auswahl sowohl auf 10 als auch auf 11 passen. – user273224

+0

ja, jetzt funktioniert es, ein einfacherer Weg wurde gepostet, aber Sie erhalten immer noch eine Stimme –

1

Bis MySQL die EXCEPT Abfrage Kombination unterstützt,

SELECT product_id 
    FROM attributes 
    WHERE product_id NOT IN (
     SELECT product_id 
     FROM attributes 
     WHERE attribute_id NOT IN (21, 23, 24) 
    ) 
    GROUP BY product_id 
UNION 
SELECT id 
    FROM products AS p 
    LEFT JOIN attributes AS a 
    ON p.id = a.product_id 
    WHERE a.product_id IS NULL 

Wenn Sie nur die Produkte mit allen angegebenen Attributen haben wollen, eine HAVING COUNT(*)=n Klausel zur ersten äußeren Abfrage hinzuzufügen, wobei ‚n‘ die Länge der Attributliste.

+0

das gleiche, funktioniert nicht im Fall (21,23,24) nach meinem Beispiel –

+0

@ Bogdan: ursprünglichen Code war für Fragenversion 3. Aktualisieren Sie die aktuelle Version (7). – outis

+0

Ich habe die Frage nicht geändert, habe es nur mit Beispielen besser erklärt. Danke für die Mühe trotzdem, hast du eine Stimme von mir –

0

Basierend auf Ihrer Einsicht Jungen, ich optimierte es sogar noch weiter und nur 1 COUNT Anweisung wie folgt verwendet:

SELECT * ,COUNT(p.product_id) AS c FROM product_attribute pa 
LEFT JOIN products p ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter_list) 
GROUP BY pa.product_id 
HAVING c=0 

Funktioniert es? :)

Bearbeiten:
Dieser Code gibt nicht den Produktnamen oder andere Felder, die es haben könnte. Dies ist die richtige:

SELECT * ,COUNT(pa.product_id) AS c FROM products p 
LEFT JOIN product_attribute pa ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter) 
GROUP BY p.product_id 
HAVING c=0