[英]MySQL: How to do a query with a limit for each WHERE filter
我需要執行按ID過濾的查詢,但是我需要限制每個ID的結果。 我不知道如何在一個查詢中執行此操作,我只能用PHP循環每個ID,對每個迭代進行查詢,然后將結果合並在一起:
$allResults = [];
$ids = [1, 2, 3, 4, 5];
foreach ($ids as $id) {
$db->query("
SELECT *
FROM example_table
WHERE example_id = $id
ORDER BY rating DESC
LIMIT 2
");
$results = $db->getResults();
$allResults = array_merge($allResults, $results);
}
上面的代碼滿足了我的需要,但是我將如何在一個查詢中而不是5個查詢循環中執行此操作?
我正在尋找這樣的東西:
SELECT *
FROM example_table
WHERE
example_id = 1 LIMIT 2 OR
example_id = 2 LIMIT 2 OR
example_id = 3 LIMIT 2 OR
example_id = 4 LIMIT 2 OR
example_id = 5 LIMIT 2
ORDER BY rating DESC
顯然,where子句中的限制會引發錯誤,但是您可以看到我正在嘗試實現的目標。 任何幫助表示贊賞。
正如@Strawberry提到的那樣,如果沒有可驗證的示例和數據,很難給出正確的答案,但這就是查詢的樣子,因為mysql還不支持組排名功能。
SELECT * FROM
(SELECT *,
@f_rank := IF(@f_rating = rating AND @f_id = id, @f_rank + 1, 1) AS rank,
@f_rating := rating,
@f_id := id
FROM example_table
WHERE id IN (1, 2, 3, 4, 5)
ORDER BY id, rating DESC) tmp_table
WHERE tmp_table.rank <= 2
您需要在此處對每個ID將所有評級從1排到n。 然后選擇前兩個ID。
您可以使用以下UNION查詢:
(SELECT * FROM example_table WHERE id = 1 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 2 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 3 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 4 ORDER BY rating DESC LIMIT 2)
UNION ALL
(SELECT * FROM example_table WHERE id = 5 ORDER BY rating DESC LIMIT 2)
這是在PHP中創建它的一種方法:
$ids = [1, 2, 3, 4, 5];
$sqlArray = array_map(function($id){
$id = (int)$id;
return "(SELECT * FROM example_table WHERE id = $id ORDER BY rating DESC LIMIT 2)";
}, $ids);
$sql = implode("\nUNION ALL\n", $sqlArray);
演示: http : //rextester.com/GNDR46232
您還應該考慮使用占位符准備查詢並綁定ID。 由於我不知道$db
的類,這里是PDO方法:
$ids = [1, 2, 3, 4, 5];
$sqlArray = array_map(function($id){
return "(SELECT * FROM example_table WHERE id = ? ORDER BY rating DESC LIMIT 2)";
}, $ids);
$sql = implode("\nUNION ALL\n", $sqlArray);
$stmt = $db->prepare($sql);
$stmt->execute($ids);
$allResults = $stmt->fetchAll(PDO::FETCH_ASSOC);
它比我想象的要復雜一些,但是您應該能夠相當容易地在PHP中以編程方式創建查詢。 您甚至不能對UNION進行直接限制,但可以有效地對具有最低級別限制的選擇進行選擇。 這是否比執行5個單獨的查詢更有效,尚不得而知。
SELECT *
FROM (SELECT *
FROM example_table
WHERE id = 1
LIMIT 2) AS id1
UNION
SELECT *
FROM (SELECT *
FROM example_table
WHERE id = 2
LIMIT 2) AS id2
UNION
SELECT *
FROM (SELECT *
FROM example_table
WHERE id = 3
LIMIT 2) AS id3
.... more UNIONS ....;
(您有一個不唯一的名為“ id”的屬性,這有點令人困惑)
基於聯合的方法都意味着對查詢中的example_id值進行硬編碼,並且無法很好地擴展到大量的example_id。
OTOH當僅查看值的子集時,將進行相對有效的查詢。
這是另一種方法...
SELECT *
FROM
(
SELECT id, max(rating) as scndrt
FROM example_table scnd
INNER JOIN (
SELECT id, max(rating) maxrt
FROM example_table
GROUP BY id) AS first
ON scnd.id=first.id
WHERE scnd.rating<first.maxrt
) AS rts
INNER JOIN example_table thrd
ON rts.id=thrd.id
AND thrd.rating IN (rts.maxrt, rts.scndrt)
這將不會返回僅包含一條記錄的ID,如果(例如)對於某個ID最高評價出現兩次,則將返回多於2條記錄。 它還需要多次傳遞數據。
我認為也可能使用查詢中的變量來解決原始問題,例如...。
SELECT @rank:=1+IF(id=@previd, @rank, 0) as ranking,
@previd=id AS currentid,
FROM (
SELECT *
FROM example_table
ORDER BY id, rating DESC
) AS src
HAVING ranking<3
我沒有使用過這樣的變量進行測試,因此可能必須使用游標將上述選擇展開到過程中,並將匹配的行寫入臨時表中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.