我可以在一列上排序/分組並在頂部顯示有限數量的結果,然後以第二個排序順序顯示其餘的結果嗎?
我有一個簡單的產品數據表,其中有一個名為special的列,可以是 1 或 0,指示產品是否特殊,應在我需要生成的產品列表中突出顯示。
最初的計劃是在我生成的任何 SELECT 查詢的頂部顯示所有特殊記錄。所有記錄都按價格排序,因此這會產生兩組結果,首先是從最便宜到最貴的所有特殊產品,在最後一個特殊產品之後,列出非特殊產品從最便宜到最貴:
SELECT * FROM table ORDER BY special DESC, price ASC
最初產品表中的特殊產品很少,上面的解決方案執行良好。
然而,現在有相當數量的特殊產品,解決方案效果不佳。我們最大的煩惱是在我們產品的一系列分頁頁面的第一頁上,最後一個特殊產品非常昂貴,然後是所有剩餘的產品,從最便宜的開始。因此,頁面要遵循的“按最便宜的排序”順序對使用者來說有點混亂。IE:
我想做的 - 在單個 SQL 查詢中 - 是在結果頂部僅顯示有限數量的特殊產品,首先是最便宜的(比如說 3),然後顯示剩餘的項目(首先是最便宜的)剩餘的特價商品出現在排序中,就好像它們不是特價商品一樣。
因此,請參閱以下範例並註意在前 3 條記錄之後,就好像 ‘special’ 上的排序順序不存在,而只是按價格排序:
A計劃
兩部分的一般技巧
ORDER BY
是有一個額外的列,說明數據來自哪個部分。要從一個部分獲取一些行,從另一個部分獲取一些行,請使用
UNION ALL
.( SELECT 1 AS part, ... FROM t WHERE special = 1 ORDER BY price ASC, id ASC LIMIT 3 ) UNION ALL ( SELECT 2 AS part, ... FROM t LEFT JOIN ( SELECT id FROM t ORDER BY price, id LIMIT 3 ) AS t1 WHERE special = 0 AND t1.id IS NULL -- to exclude the specials ) ORDER BY part ASC, price ASC
如果您不想要最便宜的 3 個特價商品,它會變得更加混亂。
此程式碼應該在 MySQL 8.0 / MariaDB 10.2 之前工作。使用 3 個特殊功能中的“WITH”的“CTE”將使程式碼在以後的版本中更清晰。
你可以用另一個包圍它
SELECT
來擺脫虛假的part
專欄。或者你可以是一個好人,並在你的 UI 中使用它來突出前 3 個是有效付費廣告。計劃 B允許 3 個“特價”與“其餘”不同的排序順序。主要技巧涉及
GROUP_CONCAT()
和FIND_IN_SET()
。SELECT all.* FROM ( SELECT GROUP_CONCAT(id) AS ids FROM ( SELECT id FROM t WHERE special = 1 ORDER BY ... -- whatever you want LIMIT 3 ) z ) AS get_ids, -- only 1 'row' CROSS JOIN ( SELECT ... FROM t ORDER BY FIND_IN_SET(id, ids) = 0, -- do specials first FIND_IN_SET(id, ids), -- order for specials price -- order for non-specials ) AS all
這很笨拙。
- 獲取 id 的有序列表。
- 遍歷整個表
- 這
ORDER BY
是棘手的部分;往上看- 如果沒有特價商品,無需更改即可使用。
- 唉,
z
而且ids
很笨拙,因為GROUP_BY
不允許LIMIT
.如果您第一次嘗試這些方法不起作用,請道歉;我很可能犯了一些錯誤。