【问题标题】:How to use pivot in sql server (without aggregates )?如何在 sql server 中使用数据透视(没有聚合)?
【发布时间】:2015-10-08 13:35:48
【问题描述】:

请帮我解决这个问题: 您将获得一个包含两列的表格: 列是以下之一:

Doctor
Professor
Singer
Actor

写一个查询输出对应occ下面的名字。格式如下:

+--------+-----------+--------+------+

| Doctor | Professor | Singer | Actor|

+--------+-----------+--------+------+

姓名必须按字母顺序排列。

示例输入

Name        Occupation
Meera       Singer
Ashely      Professor
Ketty       Professor
Christeen   Professor
Jane        Actor
Jenny       Doctor
Priya       Singer    

样本输出

Jenny    Ashley     Meera  Jane

Samantha Christeen  Priya  Julia

NULL     Ketty      NULL   Maria

注意

当没有更多与职业对应的名称时,打印“NULL”。

我尝试使用:

SELECT *
FROM
(
SELECT [Name], [Occupation] 
FROM occupations 
) AS source
PIVOT
(
    max([Name])
    FOR [occupation] IN ([Doctor], [Professor], [Singer], [Actor]) 
) as pvt;

给出以下输出:

Priya Priyanka Kristeen Samantha 

如何解决?

【问题讨论】:

  • 为什么这是必需的?作为一般原则,使用 SQL 格式化数据以用于显示目的是一种代码气味。这种结构对数据库不友好,通常应该推送到应用程序中的表示层,而不是在数据层中完成。将其移出数据库有助于确保您不会将代码引入角落,您需要在此格式之上开发进一步的 SQL。相反,将数据库的输出保持为关系/规范化的形式,这对于未来更具适应性/可维护性/灵活性。
  • @MatBailie 我也在想同样的事情,但这是一个面试问题。 ¯_(ツ)_/¯

标签: sql sql-server database


【解决方案1】:

您只需要根据每个名称的职业和字母顺序为每个名称指定一个行号。然后在您的数据透视查询中包含该行号。

CREATE TABLE Occupations (
     NAME VARCHAR(MAX),
     Occupation VARCHAR(MAX)
    )
INSERT  INTO Occupations
VALUES
        ('Samantha','Doctor'),
        ('Julia','Actor'),
        ('Maria','Actor'),
        ('Meera','Singer'),
        ('Ashley','Professor'),
        ('Ketty','Professor'),
        ('Christeen','Professor'),
        ('Jane','Actor'),
        ('Jenny','Doctor'),
        ('Priya','Singer');

SELECT
    [Doctor],
    [Professor],
    [Singer],
    [Actor]
FROM
    (SELECT 
         ROW_NUMBER() OVER (PARTITION BY Occupation ORDER BY Name) rn,
         [Name],
         [Occupation] 
     FROM 
         Occupations
    ) AS source 
PIVOT
    MAX(Name) FOR [occupation] IN ([Doctor],[Professor],[Singer],[Actor]) as pvt
ORDER BY rn


DROP TABLE Occupations

【讨论】:

  • 您可以只列出选择中的列而不是使用“select *”,而不是创建 CTE
  • @JamieD77 你能解释一下ROW_NUMBER()的需要吗
  • @Rookie_123 pivot 基本上对所有未聚合的数据进行分组。添加行号为每个名称提供另一个“分组”,使它们按职业区分,因此 MAX() 聚合不仅仅是一个名称每个职业,而是每个职业有一个名称,Row_number。
【解决方案2】:

我在 Oracle 中试过这个,似乎更容易理解:

SELECT min(Doctor), min(Professor), min(Singer), min(Actor)
FROM
( Select
ROW_NUMBER() OVER (PARTITION BY Occupation order by Name) rn, 
CASE 
WHEN Occupation = 'Doctor' then Name
end as Doctor,
CASE 
WHEN Occupation = 'Professor' then Name
end as Professor,
CASE 
WHEN Occupation = 'Singer' then Name
end as Singer,
CASE 
WHEN Occupation = 'Actor' then Name
end as Actor
from OCCUPATIONS
order by Name) a
group by rn
order by rn;

【讨论】:

    【解决方案3】:
    SELECT [Doctor], [Professor], [Singer], [Actor] FROM   
    (
        SELECT ROW_NUMBER() OVER (PARTITION BY Occupation ORDER BY Name) ROW_NO, 
        ISNULL(NULL,Name) as Name, Occupation
        FROM Occupations
    ) AS t 
    PIVOT(
        MAX(Name)
        FOR Occupation IN (
            [Doctor], 
            [Professor], 
            [Singer], 
            [Actor]
        )
    ) AS pivot_table
    ORDER BY ROW_NO;
    
    

    【讨论】:

      【解决方案4】:

      这是答案的 MYSQL 版本。由于 HACKERRANK.com 中不存在 FULL OUTER JOIN,所以难度不大

      SET @r1=0, @r2 = 0, @r3 = 0, @r4 = 0;
      
      SELECT t1.name, t2.name, t3.name, t4.name
      FROM
      
      (SELECT 
          (@r1:=@r1 + 1) AS num1, 
          Name
      FROM
          Occupations
          WHERE Occupation = 'Doctor'
      ORDER BY Name) as t1
      
      RIGHT JOIN
      
      (SELECT 
          (@r2:=@r2 + 1) AS num2, 
          Name
      FROM
          Occupations
          WHERE Occupation = 'Professor'
      ORDER BY Name) as t2
      
      ON t1.num1 = t2.num2
      
      LEFT JOIN
      
      (SELECT 
          (@r3:=@r3 + 1) AS num3, 
          Name
      FROM
          Occupations
          WHERE Occupation = 'Singer'
      ORDER BY Name) as t3
      
      ON t2.num2 = t3.num3
      
      LEFT JOIN
      
      (SELECT 
          (@r4:=@r4 + 1) AS num4, 
          Name
      FROM
          Occupations
          WHERE Occupation = 'Actor'
      ORDER BY Name) as t4
      
      ON t2.num2 = t4.num4
      

      【讨论】:

        【解决方案5】:
        SET @r1=0, @r2=0, @r3 =0, @r4=0;
        SELECT MIN(Doctor), MIN(Professor), MIN(Singer), MIN(Actor) FROM
        (SELECT CASE Occupation WHEN 'Doctor' THEN @r1:=@r1+1
                               WHEN 'Professor' THEN @r2:=@r2+1
                               WHEN 'Singer' THEN @r3:=@r3+1
                               WHEN 'Actor' THEN @r4:=@r4+1 END
               AS RowLine,
               CASE WHEN Occupation = 'Doctor' THEN Name END AS Doctor,
               CASE WHEN Occupation = 'Professor' THEN Name END AS Professor,
               CASE WHEN Occupation = 'Singer' THEN Name END AS Singer,
               CASE WHEN Occupation = 'Actor' THEN Name END AS Actor
               FROM OCCUPATIONS ORDER BY Name) AS t
        GROUP BY RowLine;
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-01
        • 2013-01-19
        • 2022-12-03
        相关资源
        最近更新 更多