【问题标题】:SQL Rank the columns based on values in each rowSQL根据每行中的值对列进行排名
【发布时间】:2020-11-23 12:32:41
【问题描述】:

我有一个类似于下面示例的 SQL 表。

对于每一行,我想添加 4 列来表示每个主题的排名(对于给定的行)。

是否可以在 SQL 中完成此操作?请帮忙。我使用 Vertica SQL。

【问题讨论】:

    标签: sql vertica


    【解决方案1】:

    一种方法是取消透视数据并重新聚合:

    select name, 
           max(case when seqnum = 1 then subject end) as rank_1,
           max(case when seqnum = 2 then subject end) as rank_2,
           max(case when seqnum = 3 then subject end) as rank_3,
           max(case when seqnum = 4 then subject end) as rank_4
    from (select s.*,
                 row_number() over (partition by name order by score desc) as seqnum      
          from ((select name, 'English' as subject, english as score from t) union all
                (select name, 'Maths', maths from t) union all
                (select name, 'Science', science from t) union all
                (select name, 'Physics', Physics from t)
               ) s
         ) s
    group by name;
    

    这是一个 dbfiddle。

    【讨论】:

    • 谢谢戈登。在表 's' 中,缺少主题列。所以我添加了这一点。否则,它说缺少主题列。但是,我仍然得到所有空白列。而且我还尝试了 rank 和 dense_rank - 但排名顺序是错误的。我错过了什么吗?
    • @anand_kk 。 . .我讨厌这样做。 name 属于那里,但在缺少的 partition by 子句中。我修正了答案并添加了一个 dbfiddle(使用 Postgres,但这是标准 SQL)。
    【解决方案2】:

    稍微复杂一点;至少在我看来。

    分成几个子查询

    WITH
    -- your input - *please* paste it as text into your question next time - 
    -- I had to re-type all of that instead of just reformatting it ...
    -- and I use "nam" instead of "name", as it's a reserved word ...
    indata(nam,english,science,physics,maths) AS (
                SELECT 'A',80,72,53,86
      UNION ALL SELECT 'B',60,65,75,52
      UNION ALL SELECT 'C',79,77,44,70
      UNION ALL SELECT 'D',69,69,55,65
    )
    ,
    -- add an in-line table with all subjects, to un-pivot with ...
    subjects(subject) AS (
                SELECT 'english'
      UNION ALL SELECT 'science'
      UNION ALL SELECT 'physics'
      UNION ALL SELECT 'maths'
    )
    ,
    -- un-pivot, by CROSS JOINing and 
    -- get a rank, based on combination of 
    -- nam and the right mark based on subject ..
    piv AS (
      SELECT
        *
      , ROW_NUMBER() OVER(
          PARTITION BY nam
          ORDER BY 
            CASE subject
              WHEN 'english' THEN english
              WHEN 'science' THEN science
              WHEN 'physics' THEN physics
              WHEN 'maths'   THEN maths
              ELSE 0
            END 
          DESC
        ) AS rnk
      FROM indata CROSS JOIN subjects
    )
    -- control query ....
    -- SELECT * FROM piv ORDER BY nam,rnk;
    -- out  nam | english | science | physics | maths | subject | rnk 
    -- out -----+---------+---------+---------+-------+---------+-----
    -- out  A   |      80 |      72 |      53 |    86 | maths   |   1
    -- out  A   |      80 |      72 |      53 |    86 | english |   2
    -- out  A   |      80 |      72 |      53 |    86 | science |   3
    -- out  A   |      80 |      72 |      53 |    86 | physics |   4
    -- out  B   |      60 |      65 |      75 |    52 | physics |   1
    -- out  B   |      60 |      65 |      75 |    52 | science |   2
    -- out  B   |      60 |      65 |      75 |    52 | english |   3
    -- out  B   |      60 |      65 |      75 |    52 | maths   |   4
    -- out  C   |      79 |      77 |      44 |    70 | english |   1
    -- out  C   |      79 |      77 |      44 |    70 | science |   2
    -- out  C   |      79 |      77 |      44 |    70 | maths   |   3
    -- out  C   |      79 |      77 |      44 |    70 | physics |   4
    -- out  D   |      69 |      69 |      55 |    65 | english |   1
    -- out  D   |      69 |      69 |      55 |    65 | science |   2
    -- out  D   |      69 |      69 |      55 |    65 | maths   |   3
    -- out  D   |      69 |      69 |      55 |    65 | physics |   4
    
    -- finally, re-pivot, by GROUP-ing by the original columns of "indata"
    -- and applying a MAX(CASE ...) to the columns I want to add.
    SELECT
      nam
    , english
    , science
    , physics
    , maths
    , MAX(CASE rnk WHEN 1 THEN subject END) AS rank_1
    , MAX(CASE rnk WHEN 2 THEN subject END) AS rank_2
    , MAX(CASE rnk WHEN 3 THEN subject END) AS rank_3
    , MAX(CASE rnk WHEN 4 THEN subject END) AS rank_4
    FROM piv
    GROUP BY
      nam
    , english
    , science
    , physics
    , maths
    ORDER BY nam;
    -- out  nam | english | science | physics | maths | rank_1  | rank_2  | rank_3  | rank_4  
    -- out -----+---------+---------+---------+-------+---------+---------+---------+---------
    -- out  A   |      80 |      72 |      53 |    86 | maths   | english | science | physics
    -- out  B   |      60 |      65 |      75 |    52 | physics | science | english | maths
    -- out  C   |      79 |      77 |      44 |    70 | english | science | maths   | physics
    -- out  D   |      69 |      69 |      55 |    65 | english | science | maths   | physics
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      • 2015-01-05
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多