【问题标题】:Mysql: Query which orders by default and rank (pin/hold up entries?)Mysql:查询默认的订单和排名(固定/保留条目?)
【发布时间】:2020-11-07 22:13:54
【问题描述】:

我有一个包含我所有产品的产品表。这些产品表被新产品永久填满。但是,我希望能够将某些产品“保留”/“固定”到返回的查询集合中的某个位置。

意思是,我想设置类似rank_index 的内容,其中包含产品在返回的查询集合中应具有的数字。

例子:

id     title                rank_index
1      An awesome product
2      Another product      5
3      Baby car
4      Green carpet         2
5      Toy        

假设默认顺序是id。但是因为 rank_index 是为具有 id 4 的产品设置的,所以我希望获得具有以下 ID 顺序的集合:1, 4, 3, 5, 2

这有可能吗? rank_index 专栏只是我的一个想法。我的意思是..我也可以在php 一侧执行此操作并执行一个普通查询,该查询仅包括products 没有rank_index 和一个仅包含productsindex_rank 并手动订购它们在php 一侧。

但是,由于这需要大量时间和处理能力,我正在寻找由数据库完成的解决方案...有什么想法吗?

顺便说一句:如果这有什么不同的话,我正在使用 Laravel 8。

亲切的问候

【问题讨论】:

    标签: php mysql sql sql-order-by ranking


    【解决方案1】:

    这是一个非常棘手的问题。如果您尝试使用其他方法设置连续值(例如 2 和 3),您会发现它们不起作用。

    可能有更简单的方法来解决这个问题。但是,这是一种蛮力方法。

    1. 它通过枚举原始表中的行来构造一个派生表。
    2. 它将所有强制排名值添加到此表中(使用left join)。
    3. 它通过枚举table1 和派生表中的空槽来连接其余值。

    所以:

    with recursive n as (
          select row_number() over (order by id) as n
          from table1 t1
         ),
         nid as (
          select n.n, t1.id
          from n left join
               table1 t1
               on t1.rank_index = n.n
         ),
         nids as (
          select n.n, coalesce(n.id, t1.id) as id
          from (select nid.*, sum(nid.id is null) over (order by nid.n) as seqnum
                from nid 
               ) n left join
               (select t1.*, row_number() over (order by id) as seqnum
                from table1 t1
                where rank_index is null
               ) t1
               on n.seqnum = t1.seqnum
         )
    select t1.*
    from nids join
         table1 t1
         on t1.id = nids.id
    order by nids.n;
    

    【讨论】:

    • 是的,这个答案是正确的。但是,在我的新问题中,我添加了“没有递归”这句话,并且我还添加了我需要一个 id 降序
    • 我很抱歉......但是当我接受上面的答案时,我没有订购桌子desc 的问题,上面的答案正在工作......但是是的,不是对于desc 我现在想出的行...
    • @Jan 。 . .这个答案说明其他两个答案不正确。
    • 它可以工作...这是一个没有递归的解决方案:dba.stackexchange.com/a/279452/218390
    • @Jan 。 . .您需要设置测试数据以查看是否确实有效。我建议:2/3;和 1/2 和 4/5 同时。您有超过 5 个插槽的更多选项。
    【解决方案2】:

    如果不为空,则使用rank_index 作为排序,否则使用id

    由于您希望 rank_index 领先于 id,因此需要进行 -0.5 调整:

    SELECT *
    FROM table
    ORDER BY IF(rank_index IS NULL, id, rank_index - 0.5)
    

    【讨论】:

    • 如果我想默认订购它,而不是按 id 而是像 performance_index 这样代表该产品的“喜欢”程度,会发生什么。只需修改您的 SQL 查询并使用performance_index 而不是id?因为对我来说,这听起来只适用于id,因为id 是一个递增值,performance_index 不会。
    • order by 可以是查询中的任何字段或从它派生的表达式。它不依赖于id 是可以排序并与rank_index - 0.5(在本例中为数字)比较的东西。
    • 但是现在出现了一个问题...我希望最新的产品始终处于领先地位。所以订购了id 降序...但这导致了一个问题,当我给rank_index 2 时,该产品是倒数第二个产品...关于如何在产品带有@ 时降序订购的任何想法987654337@2在第二位?
    • 这里有不同的类似问题吗? rank_index + 0.5 和广告 DESC 到 sql 的末尾以进行降序。如果您想更通用,rank_index 可以是双精度/浮点数,因此您可以输入 22.42.44,只要它保持在 0.5 以下。
    • 下次或现在提出一个能完整描述您的问题的问题,作为一个新问题。
    【解决方案3】:

    您可以使用IF 子句并拥有正确的号码以获得正确的顺序,所以

    CREATE TABLE table1 (
        `id` INTEGER,
        `title` VARCHAR(18),
        `rank_index` INT
    );
    
    INSERT INTO table1
        (`id`, `title`, `rank_index`)
    VALUES
        ('1', 'An awesome product', NULL),
        ('2', 'Another product', '5'),
        ('3', 'Baby car', NULL),
        ('4', 'Green carpet', '2'),
        ('5', 'Toy', NULL);
    
    SELECT *
    FROM table1
    ORDER BY IF(rank_index IS NULL, id, rank_index + .01)
    
    +----+--------------------+------------+
    | id | title              | rank_index |
    +----+--------------------+------------+
    | 1  | An awesome product | NULL       |
    | 4  | Green carpet       | 2          |
    | 3  | Baby car           | NULL       |
    | 5  | Toy                | NULL       |
    | 2  | Another product    | 5          |
    +----+--------------------+------------+
    

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      相关资源
      最近更新 更多