2016-10-08 3 views
0

Lassen Sie sich diese Frage, die ich denke, kann auf einfachere Art und Weise geschrieben werden, die besser wird durch:SQL, wie man diese Abfrage vereinfacht und Leistung erhöht?

SELECT COUNT(DISTINCT productid) 
FROM productwords pw 
WHERE productid IN 
(SELECT productid FROM productwords pw JOIN words w 
    ON pw.wordid = w.id WHERE word = 'nike') 
AND productid IN 
(SELECT productid FROM productwords pw JOIN words w 
    ON pw.wordid = w.id WHERE word = 'free') 

Ziel der Abfrage ist die Anzahl der unterschiedlichen productIds zu bekommen, die Worte haben = both ‚Nike‘ und ' frei'.

Danke!

+0

Post einige Beispieldaten und das gewünschte Ergebnis. –

+0

Bitte schreiben Sie Ihre Tabellenstruktur und einige Beispieldaten ... – HorusKol

Antwort

4

Wenn ich Ihre Frage richtig zu verstehen, sollte dies besser sein, nur eine join mit:

SELECT COUNT(DISTINCT productid) 
FROM productwords pw 
    JOIN words w ON pw.productid = w.id 
WHERE word IN ('nike','free') 

Ihre aktuelle Abfrage on pw = w.id eigentlich nicht korrekt ist. Welches Feld Sie auch immer versuchen möchten join sollte oben enthalten sein. Ich vermutete productid, aber vielleicht seine wordid statt ...

+0

Ich denke, diese Abfrage gibt eine Anzahl von Produkten zurück, die * entweder * der Schlüsselwörter entspricht. Dies könnte sein, was OP beabsichtigt, aber ich lese die Spezifikation ein wenig anders ... eine Zählung zurückgeben ... aber * nur * jene Produkte einschließen, die Schlüsselwort "nike" UND Matche Stichwort "frei" entsprechen. (Wenn ein Produkt mit "nike" übereinstimmt, aber nicht mit "free" übereinstimmt, wird dieses Produkt nicht berücksichtigt.) – spencer7593

+0

Sie haben Recht, die zurückgegebenen Produkte müssen mit beiden Keywords übereinstimmen, dh sowohl "nike" als auch " frei". – Louisa

+0

Ich habe den Fehler in "on pw = w.id" behoben - es sollte "on pw.wordid = w.id" sein – Louisa

0

Sie können einfach die Abfrage durch ähnliche

select count(*), w.word from product p left join words w on w.id = p.word_id where w.name = 'nike' or w.name = 'free' group by w.name 

Hoffnung zu tun, diese Abfrage Ihre Frage beantworten. Sie auch von

where w.name in ('nike', 'free') 

filtern können, wenn Sie viele Zeilen haben (wir 10.000 sagen ++) Sie so

SELECT count(*), w.name from product p JOIN (select id, name from words where name = 'nike' or name = 'free') w on w.id = p.word_id group by w.name 
+0

Dies ist in der Tat eine etwas einfachere Abfrage. Dies führt aber auch zu einem Ergebnis, das signifikant * anders * ist als das Ergebnis der OP-Abfrage. Dies gibt eine Anzahl von Zeilen zurück, die mit jedem Wort in Beziehung stehen. Dies mag das Ergebnis sein, das OP verlangt, aber ich lese die Spezifikation ganz anders und gebe ein Äquivalent der OP-Abfrage zurück. – spencer7593

+0

oh sorry, ich habe vergessen, die Filter einzufügen. Ich werde meine Antwort bearbeiten. –

0

Sehr seltsam verbessern könnte, dass die Fremdschlüsselspalte in den productswords (Produkt Schwerter ?) Tabelle heißt pw und nicht . (Aber es ist nur ein Spaltenname, können wir es nennen, was wir wollen. Wenn der Fremdschlüssel etwas anderes tatsächlich genannt wird, dann ersetzen pw.pw in den Abfragen unten mit pw.column_name ...)

Um Produkte zu finden, die beide passen von die zwei Wörter, dh, geben nur ein Produkt zurück, wenn es mit dem Wort "nike" übereinstimmt und wenn es mit dem Wort "free" übereinstimmt ...

Wir können eine Join-Operation verwenden, kombiniert mit einer GROUP BY und einer HAVING Klausel. ..

SELECT pw.productid 
    FROM productwords pw 
    JOIN words w 
    ON w.id = pw.pw 
    AND w.word IN ('nike','free') -- keywords to match 
    GROUP BY pw.productid 
HAVING COUNT(DISTINCT w.word) = 2 -- number of keywords to match 

Um nur eine Anzahl zu bekommen, können wir das in Parens und Referen umwandeln ce es als Inline-Ansicht ...

SELECT COUNT(1) 
    FROM (SELECT pw.productid 
      FROM productwords pw 
      JOIN words w 
       ON w.id = pw.pw 
      AND w.word IN ('nike','free') -- keywords you are looking for 
      GROUP BY pw.productid 
      HAVING COUNT(DISTINCT w.word) = 2 -- number of keywords to match 
     ) v 

Es andere Abfragemuster sind, die ein gleichwertiges Ergebnis zurückkehren wird.

Zum Beispiel ein EXISTS (correlated subquery) Muster unter Verwendung von nur die Produkte zu erhalten, die beide der angegebenen Wörter passen ...

SELECT pw.productid 
    FROM productwords pw 
    WHERE EXISTS (SELECT 1 
        FROM words w 
        WHERE w.id = pw.pw  -- related to row on outer query 
        AND w.word IN ('nike','free') 
       ) 
GROUP BY pw.productid 
HAVING COUNT(DISTINCT pw.pw) = 2 

Um nur eine Zählung wieder wickeln, dass in Pars und darauf verweisen als Inline-Ansicht.


Für nicht-triviale Sätze, mit geeigneten Indizes zur Verfügung können erheblich Leistung beiden Abfragen verbessern.Zum Beispiel

... ON productswords (pw, productid) 
    ... ON words (word, id)