sql >> Databasteknik >  >> RDS >> Mysql

Att skriva en komplex MySQL-fråga

Jag skulle vara frestad att ha en underfråga som får alla ord en person har lärt sig och slå ihop det mot sig själv, med orden GROUP_CONCAT tillsammans med en räkning. Så ger:-

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

Så underfrågan skulle vara ungefär:-

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

ger

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

Förena sedan resultaten av detta mot de andra tabellerna, leta efter artiklar där huvudkoden matchar men ingen av de andra hittas.

Något liknande detta (även om det inte testats eftersom inga testdata):-

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 

EDIT - uppdaterad för att utesluta artiklar med mer än 10 ord som inte redan är inlärda.

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 - försök att kommentera ovanstående fråga:-

Detta väljer bara kolumnerna

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

Den här underfrågan får vart och ett av orden inlärt, tillsammans med en kommaseparerad lista över orden med en större order_learned. Detta är för ett visst användar-ID

(
    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 

Detta är bara för att få artiklarna som orden (dvs. orden som lärts från underfrågan ovan) används i

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

Den här underfrågan får de artiklar som innehåller mindre än 10 ord som ännu inte har lärt sig av den specifika användaren.

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

Denna koppling är till för att hitta artiklar som har ord i den kommaavgränsade listan från den första underfrågan (dvs. ord med en större order_learned). Detta görs som en LEFT OUTER JOIN eftersom jag vill utesluta alla ord som hittas (detta görs i WHERE-satsen genom att markera 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. Hur återställer man postgres primära nyckelsekvens när den faller ur synk?

  2. Vilken datamaskeringsfunktion ska jag använda?

  3. Jämför datum lagrade som sträng med Datetime

  4. Uppdatera en materialiserad vy automatiskt med hjälp av en regel eller avisering