【问题标题】:Sort to have non-consecutive column values排序以具有不连续的列值
【发布时间】:2019-03-27 16:11:29
【问题描述】:

这在 mysql 查询中可能吗?当前数据表为:

id - fruit - name
1 - Apple - George
2 - Banana - George
3 - Orange - Jake
4 - Berries - Angela

name 列中,我想对其进行排序,以便在我的select 查询中没有连续的名称。

我的愿望输出是,名称列中没有连续的george

id - fruit - name
1 - Apple - George
3 - Orange - Jake
2 - Banana - George
4 - Berries - Angela

提前致谢。

【问题讨论】:

  • 有两个单独的查询,做交替提取。
  • 你的 MySQL 服务器版本是多少?
  • 这很难。这与所谓的排序相反 :-) 如果你有 Angela-George-George-George 怎么办?没有办法对这四个进行排序,以便将所有乔治分开。在这种情况下要做什么查询?崩溃?
  • @MadhurBhaiya 5.5.56-MariaDB 服务器
  • 您已将您的请求标记为“sql”。但是您不是在寻找有关 SQL 的答案(例如,如何修复您的 SQL 查询或如何在 SQL 中应用您的算法——您既没有查询也没有算法)。您正在寻找一种算法。因此,您应该删除与数据库相关的标签并用“算法”标签替换它们。

标签: mysql sql algorithm sorting columnsorting


【解决方案1】:

在 MySQL 8+ 中,您可以这样做:

order by row_number() over (partition by name order by id)

在早期版本中,您可以使用变量来执行此操作。

【讨论】:

    【解决方案2】:

    另一个想法...

    DROP TABLE IF EXISTS my_table;
    
    CREATE TABLE my_table
    (id SERIAL PRIMARY KEY
    ,name VARCHAR(12) NOT NULL
    );
    
    INSERT INTO my_table VALUES
    (1,'George'),
    (2,'George'),
    (3,'Jake'),
    (4,'Angela');
    
    SELECT x.* 
      FROM my_table x
      JOIN my_table y 
        ON y.name = x.name 
       AND y.id <= x.id
     GROUP 
        BY x.id
     ORDER
        BY COUNT(*)
         , id;
    
    +----+--------+
    | id | name   |
    +----+--------+
    |  1 | George |
    |  3 | Jake   |
    |  4 | Angela |
    |  2 | George |
    +----+--------+
    

    【讨论】:

      【解决方案3】:

      以下解决方案适用于all the MySQL versions,尤其是版本

      • Derived table 中,首先使用nameid 对实际表进行排序。
      • 然后,在具有相同name 值的所有行中确定特定行的行号。
      • 现在,使用此结果集并按 行号 值对其进行排序。因此,所有具有 row number = 1 的行将首先出现(对于所有不同的 name 值)等等。因此,不会出现连续的name 行。

      您可以使用User-defined Session Variables 尝试以下操作:

      SELECT dt2.id,
             dt2.fruit,
             dt2.name
      FROM   (SELECT @row_no := IF(@name_var = dt1.name, @row_no + 1, 1) AS row_num,
                     dt1.id,
                     dt1.fruit,
                     @name_var := dt1.name                               AS name
              FROM   (SELECT id,
                             fruit,
                             name
                      FROM   your_table_name
                      ORDER  BY name,
                                id) AS dt1
                     CROSS JOIN (SELECT @row_no := 0,
                                        @name_var := '') AS user_init_vars) AS dt2
      ORDER  BY dt2.row_num,
                dt2.id  
      

      DB Fiddle DEMO

      【讨论】:

      • 嗨,我正在测试这种方法,但是当我测试添加另一个乔治行时,它仍然显示为连续的db-fiddle.com/f/8amYX6iRu8AsnYXJYz15DF/0
      • @bumbumpaw 这就是 Thorsten suggested 。如果您的同名行多于其他行,则排序将不起作用。在这种情况下很难实现。
      • 嗯,好的,我明白了。我需要使用 php 对其进行操作,然后将结果保存到另一个数组中。类似的东西。
      • @bumbumpaw 即使 PHP 也帮不上忙。假设您总共有 10 行,其中 George 有 6 行。你如何适应所有乔治的名字,使它们不连续
      • @bumbumpaw:你改变的小提琴说明了为什么这如此困难。对三个 George、一个 Jake 和一个 Angela 进行排序的唯一解决方案是让 Jake 和 Angela 排在第 2 和第 4 行。然而,仅从数据库的角度来看,Jake 就像 Angela;他们都在表中只有一行,那么应用什么规则来制作一行#2和一行#4?您真正需要的是该任务的算法。然后使用编程语言而不是 SQL 来应用该算法可能会更容易。
      【解决方案4】:

      这是我的算法:

      1. 统计每个名字出现的频率
      2. 按频率降序和名称排序
      3. 分割成与最大频率一样大的分区
      4. 每个分区内的行数
      5. 按行号和分区号排序

      示例:名称 A、B、C、D、E

       step 1 and 2
       ------------
       AAAAABBCCDDEE
      
       step 3 and 4
       ------------
       12345     
       AAAAA
       BBCCD
       DEE
      
       step 5
       ------
       ABDABEACEACAD
      

      查询:

      with counted as
      (
        select id, fruit, name, count(*) over (partition by name) as cnt
        from mytable 
      )
      select id, fruit, name
      from counted
      order by
        (row_number() over (order by cnt desc, name) - 1) % max(cnt) over (),
        row_number() over (order by cnt desc, name);
      

      从 MySQL 8 或 MariaDB 10.2 开始提供公共表表达式(WITH 子句)和窗口函数(聚合 OVER)。在此之前,您可以退回到子查询,但这会使相同的查询变得很长且难以阅读。我想您也可以以某种方式使用变量。

      DB 小提琴演示:https://www.db-fiddle.com/f/8amYX6iRu8AsnYXJYz15DF/1

      【讨论】:

        猜你喜欢
        • 2016-11-11
        • 1970-01-01
        • 2019-10-31
        • 1970-01-01
        • 2011-06-29
        • 2021-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多