SQL 版本:MySQL 8.0 或 SQL Server
SQL小提琴:https : //www.db-fiddle.com/f/wcHeXkcynUiYP3qzryoYJ7/6
我有一個影像表和一個鏈接到這些影像的標簽表。
================================== ===================================================
| tb_images | | tb_imagetags |
================================== ===================================================
| f_imageID | f_imagefilename | | f_imagetagID | f_imagetagimage | f_imagetagname |
---------------------------------- ---------------------------------------------------
| 1 | 1.jpg | | 10 | 1 | November |
| 2 | 2.jpg | | 11 | 1 | 2021 |
| 3 | 3.jpg | | 12 | 2 | November |
================================== | 13 | 2 | 2020 |
| 14 | 3 | December |
| 15 | 3 | 2020 |
===================================================
我希望能夠將 (2) 個標簽傳遞給查詢,并讓它只選擇與兩個標簽匹配的影像。例如,我想通過November并2021讓它只回傳1.jpg.
如果我做這樣的事情:
SELECT f_imageID, f_imagefilename
FROM tb_images
LEFT JOIN tb_imagetags
ON f_imagetagimage = f_imageID
WHERE f_imagetagname = 'November'
OR f_imagetagname = '2021'
但這會回傳:
f_imageID f_imagefilename
================================
1 1.jpg
1 1.jpg
2 2.jpg
如何重寫此查詢以僅獲取與兩個標簽匹配的影像?
uj5u.com熱心網友回復:
問題是您的資料跨不同行相關。如果所有資料都在同一行中,那就很容易了
SELECT * FROM blah WHERE month = nov and year = 2021
當它在不同的行中時,您希望像正在做的那樣獲得兩行。
..但是你只想要那些有兩行的影像。如果只有一行(例如僅 11 月或僅 2021 年),您不希望那樣
有多種方法可以做到。一種是將標簽表加入到自身中,將一側過濾到幾個月,另一邊過濾到幾年
tb_imagetags tmonth
JOIN tb_imagetags tyear
ON
tmonth.f_imagetagname = 'November' AND
tyear.f_imagetagname = '2021' AND
tmonth.f_imagetagimage = tyear.f_imagetagimage
這將隱式地將 11 月和 2021 年“放在同一行”,因此只有具有這兩個標簽的影像才會出現在連接結果中。
..但我們執行此類“跨行”查詢的通常方式可能是在對它們進行分組后檢查計數,或者檢查最小值是否為 x,最大值為 y,例如:
SELECT f_imageID, f_imagefilename
FROM tb_images
INNER JOIN tb_imagetags
ON f_imagetagimage = f_imageID
WHERE f_imagetagname = 'November'
OR f_imagetagname = '2021'
GROUP BY f_imageID
HAVING COUNT(*) = 2
或者
HAVING MIN(f_imagetagname) = '2021' AND MAX( f_imagetagname) = 'November'
如果標簽名稱不同,則計數有效。如果您可以意外地將 11 月翻倍,那么它也會將這些翻倍。min max 僅適用于兩個標簽.. 你也可以使用類似的東西
HAVING SUM(CASE f_imagetagname WHEN 'November' THEN 1 WHEN '2021' THEN 2 END) = 3
這對任意數量的標準都有好處,您只需增加 2 的冪,因此對于 3 個標簽,當 1、2、4 并要求總和為 7 時,您也可以使用任何冪,例如以 10 為底。 . 上漲 1,10,100 并要求總和為 111..
您還可以多次詢問是否存在相關行:
SELECT f_imageID, f_imagefilename
FROM tb_images
WHERE
EXISTS(SELECT null FROM tb_imagetags WHERE f_imagetagimage = f_imageID AND f_imagetagname = 'November')
AND
EXISTS(SELECT null FROM tb_imagetags WHERE f_imagetagimage = f_imageID AND f_imagetagname = '2021')
如果存在符合條件的行,則 EXISTS 回傳 true:他的 sql 表示“影像中有一些標記行是 11 月,并且有一些(其他)標記行是 2021 年”
無論您做什么,您都需要想辦法將資料在存在的 N 行中分組,然后做一些事情,使這些行作為一個組滿足條件。這是一個技巧,因為我們通常不會像人類那樣思考這些設定的術語,我們傾向于“逐行”思考更多
uj5u.com熱心網友回復:
一種方法使用聚合:
SELECT i.f_imageID, i.f_imagefilename
FROM tb_images i
INNER JOIN tb_imagetags it
ON it.f_imagetagimage = i.f_imageID
GROUP BY i.f_imageID, i.f_imagefilename
HAVING SUM(f_imagetagname = 'November') > 0 AND
SUM(f_imagetagname = '2021') > 0;
我們的想法是通過影像和匯總,然后斷言都November和2021每個影像組中出現的變數值,發現一些記錄。
這是您更新的 DB Fiddle。
uj5u.com熱心網友回復:
你可以為我們存在
SELECT DISTINCT f_imageID, f_imagefilename
FROM tb_images
LEFT JOIN tb_imagetags fi2
ON f_imagetagimage = f_imageID
WHERE f_imagetagname = 'November'
AND EXISTS(SELECT 1 FROM tb_imagetags Fi WHERE f_imagetagname = '2021' AND fi.f_imageID = fi2.f_imageID)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/399384.html
