【问题标题】:SQL to sort columns within each row and order rows based on thisSQL 对每行中的列进行排序并基于此对行进行排序
【发布时间】:2013-09-14 04:28:09
【问题描述】:

我可以使用什么 SQL 选择查询来对每一行进行排序,然后对已排序的行进行排序?

例如:表格标签(c1、c2、c3、c4)

2,5,8,4
2,1,6,7
5,2,9,3

查询必须给出:

1,2,6,7
2,3,5,9
2,4,5,8

【问题讨论】:

  • 在应用层做,而不是在数据库里。
  • @Yosi:易于使用ORDER BY,但我不知道如何对每行中的列进行排序
  • @slashmais 如果列数是固定的(而且很小),一个非常复杂的CASE 可以解决它。 只有 24 种可能的四列排序 (4!) :-) :-)
  • 也许您可以使用CROSS APPLY 创建一些复杂的查询,但我认为这几乎是不可能的。可能你需要调用外部编程来完成这项工作。
  • @fancyPants:我正在使用 sqlite 数据库浏览器,希望可以通过查询来完成,而无需编写应用程序

标签: sql sqlite sorting select


【解决方案1】:

这只是开始,也许不是最“干净”的代码,但它会工作

SELECT CASE WHEN C1 < C2 THEN 
                CASE WHEN C1 < C3 THEN C1 ELSE C3 END
            ELSE
                CASE WHEN C2 < C3 THEN C2 ELSE C3 END
       END

From YourTable

这将首先选择最小的元素。 再多三个,你就可以走了.. 获得此结果集后,您可以按第一列排序。

【讨论】:

  • 使比较有点烦人,但它是相同的概念。
【解决方案2】:
SELECT
MIN(c1, c2, c3, c4) AS new_c1,
CASE MIN(c1, c2, c3, c4) WHEN c1 THEN MIN(c2, c3, c4)
                         WHEN c2 THEN MIN(c1, c3, c4)
                         WHEN c3 THEN MIN(c1, c2, c4)
                         WHEN c4 THEN MIN(c1, c2, c3)
                         END AS new_c2,
CASE MAX(c1, c2, c3, c4) WHEN c1 THEN MAX(c2, c3, c4)
                         WHEN c2 THEN MAX(c1, c3, c4)
                         WHEN c3 THEN MAX(c1, c2, c4)
                         WHEN c4 THEN MAX(c1, c2, c3)
                         END AS new_c3,
MAX(c1, c2, c3, c4) AS new_c4
FROM tab
ORDER BY new_c1, new_c2, new_c3, new_c4
  • 看到它在sqlfiddle 中工作
  • 有关min()max() 函数的信息,请参见here

引用:

请注意,当 max() [和 min()] 有 2 个或更多参数时,它是一个简单的函数,但如果只给定一个参数,则作为聚合函数运行。

【讨论】:

    【解决方案3】:

    可能的解决方案:

    CREATE TEMPORARY TABLE nums2
    (
       Row int,
       V int
    );
    
    INSERT INTO nums2
    SELECT *     
    FROM
    (
        SELECT rowid Row, c1 V FROM nums
        UNION ALL
        SELECT rowid Row, c2 V FROM nums
        UNION ALL
        SELECT rowid Row, c3 V FROM nums
        UNION ALL
        SELECT rowid Row, c4 V FROM nums
    ) 
    ORDER BY Row, V;
    
    SELECT n1.V v1, n2.V v2, n3.V v3, n4.V v4
        FROM nums2 n1
        INNER JOIN nums2 n2 ON n1.Row = n2.Row AND n2.rowid = n1.rowid + 1
        INNER JOIN nums2 n3 ON n1.Row = n3.Row AND n3.rowid = n1.rowid + 2
        INNER JOIN nums2 n4 ON n1.Row = n4.Row AND n4.rowid = n1.rowid + 3
        WHERE ((n1.rowid - 1) % 4 = 0)
        ORDER BY n1.V, n2.V, n3.V, n4.V
    

    它使用一个临时表 (nums2) 来保存“线性化”行,并使用隐藏列 rowid 将行分组。

    测试人员:http://sqlfiddle.com/#!7/d0232/38

    最后一个选择可以简化一点:

    SELECT n1.V v1, n2.V v2, n3.V v3, n4.V v4
        FROM nums2 n1
        INNER JOIN nums2 n2 ON n2.rowid = n1.rowid + 1
        INNER JOIN nums2 n3 ON n3.rowid = n1.rowid + 2
        INNER JOIN nums2 n4 ON n4.rowid = n1.rowid + 3
        WHERE ((n1.rowid - 1) % 4 = 0)
        ORDER BY n1.V, n2.V, n3.V, n4.V
    

    因为WHERE 表达式将“选择”每一行的最小值。

    测试人员:http://sqlfiddle.com/#!7/d0232/39

    查询很容易扩展。

    【讨论】:

      【解决方案4】:

      您可以将表格转为(row_nr, col_nr, value) 格式。然后您可以对其进行排序,并将其还原为(row_nr, val1, val2, val3, val4) 格式。

      ; with  with_numbers as 
              (
              select  row_number() over (order by c1) rn
              ,       *
              from    tab
              )
      ,       normalized(rn, nr) as 
              (
              select  rn, c1 from with_numbers
              union all
              select  rn, c2 from with_numbers
              union all
              select  rn, c3 from with_numbers
              union all
              select  rn, c4 from with_numbers
              )
      ,       normalized_with_number as
              (
              select  row_number() over (partition by rn order by nr) rn2
              ,       *
              from    normalized
              )
      ,       sorted as
              (
              select  max(case when rn2 = 1 then nr end) c1
              ,       max(case when rn2 = 2 then nr end) c2
              ,       max(case when rn2 = 3 then nr end) c3
              ,       max(case when rn2 = 4 then nr end) c4
              from    normalized_with_number
              group by
                      rn      
              )
      select  *
      from    sorted
      order by
              c1
      ,       c2
      ,       c3
      ,       c4
      

      See it working at SQL Fiddle.

      【讨论】:

      • 他要求 SQLite,所以没有 CTE 也没有 row_number :-) :-)
      • @xanatos:哈哈... 废话。我以为我很聪明:D
      猜你喜欢
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      相关资源
      最近更新 更多