Mysql

我可以在一列上排序/分組並在頂部顯示有限數量的結果,然後以第二個排序順序顯示其餘的結果嗎?

  • August 26, 2021

我有一個簡單的產品數據表,其中有一個名為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.

如果您第一次嘗試這些方法不起作用,請道歉;我很可能犯了一些錯誤。

引用自:https://dba.stackexchange.com/questions/298564