sql >> Databáze >  >> RDS >> Mysql

Psaní komplexního MySQL dotazu

Byl bych v pokušení mít dílčí dotaz, který dostane všechna slova, která se člověk naučil, a spojit je proti sobě se slovy GROUP_CONCAT spolu s počtem. Takže dávám:-

Octopus, NULL, 0
Dog, "Octopus", 1
Spoon, "Octopus,Dog", 2

Takže dílčí dotaz by byl něco jako:-

SELECT sub0.idwords, GROUP_CONCAT(sub1.idwords) AS excl_words, COUNT(sub1.idwords) AS older_words_cnt
FROM words_learned sub0
LEFT OUTER JOIN words_learned sub1
ON sub0.userId = sub1.userId
AND sub0.order_learned < sub1.order_learned
WHERE sub0.userId = 1
GROUP BY sub0.idwords

dávání

idwords    excl_words    older_words_cnt
1          NULL          0
2          1             1
3          1,2           2

Poté výsledky spojte s ostatními tabulkami a vyhledejte články, ve kterých se hlavní idwords shodují, ale žádná jiná nebyla nalezena.

Něco takového (ačkoli to nebylo testováno jako žádná testovací data):-

SELECT sub_words.idwords, words_inc.idArticle
(
    SELECT sub0.idwords, SUBSTRING_INDEX(GROUP_CONCAT(sub1.idwords), ',', 10) AS excl_words, COUNT(sub1.idwords) AS older_words_cnt
    FROM words_learned sub0
    LEFT OUTER JOIN words_learned sub1
    ON sub0.userId = sub1.userId
    AND sub0.order_learned < sub1.order_learned
    WHERE sub0.userId = 1
    GROUP BY sub0.idwords
) sub_words
INNER JOIN words words_inc
ON sub_words.idwords = words_inc.idwords
LEFT OUTER JOIN words words_exc
ON words_inc.idArticle = words_exc.idArticle
AND FIND_IN_SET(words_exc.idwords, sub_words.excl_words)
WHERE words_exc.idwords IS NULL
ORDER BY older_words_cnt
LIMIT 100 

UPRAVIT – aktualizováno tak, aby byly vyloučeny články s více než 10 slovy, která ještě nejsou naučena.

SELECT sub_words.idwords, words_inc.idArticle,
sub2.idArticle, sub2.count, sub2.content
FROM
(
    SELECT sub0.idwords, GROUP_CONCAT(sub1.idwords) AS excl_words, COUNT(sub1.idwords) AS older_words_cnt
    FROM words_learned sub0
    LEFT OUTER JOIN words_learned sub1
    ON sub0.userId = sub1.userId
    AND sub0.order_learned < sub1.order_learned
    WHERE sub0.userId = 1
    GROUP BY sub0.idwords
) sub_words 
INNER JOIN words words_inc
ON sub_words.idwords = words_inc.idwords
INNER JOIN
(
    SELECT a.idArticle, a.count, a.content, SUM(IF(c.idwords_learned IS NULL, 1, 0)) AS unlearned_words_count
    FROM Article a
    INNER JOIN words b
    ON a.idArticle = b.idArticle
    LEFT OUTER JOIN words_learned c
    ON b.idwords = c.idwords
    AND c.userId = 1
    GROUP BY a.idArticle, a.count, a.content
    HAVING unlearned_words_count < 10
) sub2
ON words_inc.idArticle = sub2.idArticle
LEFT OUTER JOIN words words_exc
ON words_inc.idArticle = words_exc.idArticle
AND FIND_IN_SET(words_exc.idwords, sub_words.excl_words)
WHERE words_exc.idwords IS NULL
ORDER BY older_words_cnt
LIMIT 100

EDIT - pokus o okomentování výše uvedeného dotazu:-

Tím pouze vyberete sloupce

SELECT sub_words.idwords, words_inc.idArticle,
sub2.idArticle, sub2.count, sub2.content
FROM

Tento dílčí dotaz získá každé naučené slovo spolu s čárkou odděleným seznamem slov s větším order_learned. Toto je pro konkrétní ID uživatele

(
    SELECT sub0.idwords, GROUP_CONCAT(sub1.idwords) AS excl_words, COUNT(sub1.idwords) AS older_words_cnt
    FROM words_learned sub0
    LEFT OUTER JOIN words_learned sub1
    ON sub0.userId = sub1.userId
    AND sub0.order_learned < sub1.order_learned
    WHERE sub0.userId = 1
    GROUP BY sub0.idwords
) sub_words 

To jen proto, aby se v článcích použila slova (tj. slova naučená z výše uvedeného dílčího dotazu)

INNER JOIN words words_inc
ON sub_words.idwords = words_inc.idwords

Tento dílčí dotaz získá články, které obsahují méně než 10 slov, která se konkrétní uživatel ještě nenaučil.

INNER JOIN
(
    SELECT a.idArticle, a.count, a.content, SUM(IF(c.idwords_learned IS NULL, 1, 0)) AS unlearned_words_count
    FROM Article a
    INNER JOIN words b
    ON a.idArticle = b.idArticle
    LEFT OUTER JOIN words_learned c
    ON b.idwords = c.idwords
    AND c.userId = 1
    GROUP BY a.idArticle, a.count, a.content
    HAVING unlearned_words_count < 10
) sub2
ON words_inc.idArticle = sub2.idArticle

Toto spojení slouží k nalezení článků, které obsahují slova v seznamu oddělených čárkami z 1. dílčího dotazu (tj. slova s ​​větším pořadím_naučení). To se provádí jako LEFT OUTER JOIN, protože chci vyloučit všechna nalezená slova (to se provádí v klauzuli WHERE kontrolou NULL)

LEFT OUTER JOIN words words_exc
ON words_inc.idArticle = words_exc.idArticle
AND FIND_IN_SET(words_exc.idwords, sub_words.excl_words)
WHERE words_exc.idwords IS NULL
ORDER BY older_words_cnt
LIMIT 100


  1. Je aktualizace MySQL, která mění více sloupců, neatomická?

  2. Jak optimalizovat MySQL Boolean Full-Text Search? (Nebo čím to nahradit?) - C#

  3. Odstraňování problémů Žádný takový soubor nebo adresář při spuštění `php app/console doctrine:schema:create`

  4. Jak hodnoty NULL ovlivňují výkon při vyhledávání v databázi?