【问题标题】:SQL Pivot and Distinct from new ColumnsSQL Pivot 和 Distinct from new Columns
【发布时间】:2020-11-24 20:21:27
【问题描述】:

我有一个名为 ADMIN 的表,最初看起来像这样

KEY           VALUE
Version1      2019_RQK@2019
Version2      2019_RQK@2020
Version2      2019_RQK@2021
Version2      2019_RQK@2022
Version2      2020_TKA@2020
Version2      2020_TKA@2021
Version2      2020_TKA@2022
Version2      2020_TKA@2023

我正试着把它改成这样

VERSION       YEAR1      YEAR2      YEAR3      YEAR4     
2019_RQK      2019       2020       2021       2022
2020_TKA      2020       2021       2022       2023

我编写了一些 SQL 以获得 [VALUE] 列的左右版本,但我不知道如何压缩它,以便它只显示 DISTINCT[VALUE] 列的左侧.我尝试使用 distinct,但它仍然会出现相同的重复条目,这是我到目前为止所写的,我不知道 PIVOT 函数是否可以在这里工作我尝试了一些最终没有正确的事情。

SELECT DISTINCT LEFT([VALUE], 7) AS VERSION, RIGHT([VALUE], 4) AS YEAR
FROM ADMIN
WHERE [KEY] LIKE '%VERSION%'

只是给我,不知道如何在同一个查询中更改它

VERSION      YEAR
2019_RQK     2019
2019_RQK     2020
2019_RQK     2021
2019_RQK     2022
2020_TKA     2020
2020_TKA     2021
2020_TKA     2022
2020_TKA     2023

【问题讨论】:

    标签: sql sql-server tsql pivot


    【解决方案1】:

    所以,是的,您需要一个 PIVOT 表来执行此操作。您可以通过 here 了解所有关于它们的信息,其中有一个非常简单(而且快速!)的演练,以了解它为何如此神奇。

    要透视此表,我们需要为 YEAR1、YEAR2 等添加一列。这样它们就可以成为我们的标题/新列。我会用一个基本的ROW_NUMBER 函数来做到这一点。我知道这个示例每个条目最多有 4 个新列,因此我将它们硬编码,但上面的链接说明了如果最大列数未知,如何动态生成 IN 语句。

    请注意,我的测试表是用 col1 和 col2 创建的,因为我很懒。您应该将它们交换为实际的列名。

    
    SELECT * FROM (
      -- we start with your basic table, as you provided
      SELECT 
        LEFT(col2, 7) AS VERSION, 
        RIGHT(col2, 4) AS YEAR, 
        ROW_NUMBER() OVER (partition by LEFT(col2, 7) order by RIGHT(col2, 4)) as YearNum /* sort these by the proper year, so we don't get of order */
      FROM ADMIN
      WHERE col1 LIKE '%VERSION%'
    ) versionResults 
    PIVOT (
      max([YEAR]) -- grab the year
      for [YearNum] -- this column holds our new column headers
      in ( /* these are the possible YearNum values, now our new column headers */
        [1],
        [2],
        [3],
        [4]
      )
    ) as pivotResults
    

    Demo here.

    【讨论】:

      【解决方案2】:

      您还需要提取前 4 个字符作为“基准年”,然后从“基准年”中减去“年”(并加 1)以获得整数值 (1-4) 并将其用作PIVOT 列表。

      Example Fiddle

      这是“困难”的原因是您在 1 列中存储了 3 个键值。至少它的固定宽度很容易持续分开。

      如果 VALUE 列包含不同格式的数据,这将不起作用。

      CREATE TABLE Admin
      ( Key1 char(8)
      , Val  char(13)
      );
      
      INSERT INTO Admin (Key1, Val)
      VALUES
        ('Version1','2019_RQK@2019')
      , ('Version2','2019_RQK@2020')
      , ('Version2','2019_RQK@2021')
      , ('Version2','2019_RQK@2022')
      , ('Version2','2020_TKA@2020')
      , ('Version2','2020_TKA@2021')
      , ('Version2','2020_TKA@2022')
      , ('Version2','2020_TKA@2023');
      
      WITH Src AS (
      SELECT
            Version  = SUBSTRING(Val,1,8)
          , Year     = CAST(SUBSTRING(Val,10,4) as int)
          , YearCt   = CAST(SUBSTRING(Val,10,4) as int) - CAST(SUBSTRING(Val,1,4) as int) + 1
      FROM Admin
      )
      SELECT
            pvt.Version
          , Year1 = pvt.[1]
          , Year2 = pvt.[2]
          , Year3 = pvt.[3]
          , Year4 = pvt.[4]
      FROM Src
      PIVOT (MAX(Year) FOR YearCt IN ([1],[2],[3],[4])) pvt;
      

      【讨论】:

      • 您好,五个答案基本相同,但您似乎基于一些基本假设,即版本名称的年份和可能的发布年份是连续的/相隔一定数量。例如,如果我将最后一个数据行更改为2020_TKA@2026,当我玩您的演示时,您的结果中该字段为null
      • @CoffeeNeedCoffee 不错。我确实做出了这个假设,甚至没有意识到我有(我在我的生产环境中编写了类似的查询来处理保证的顺序值,所以我冲进去了)。
      【解决方案3】:

      就选择当前插入的年份而言,在数据更改时不对查询应用任何操作

      DECLARE @cols  AS NVARCHAR(MAX),  @query AS NVARCHAR(MAX)
      
      SET @cols = ( SELECT STRING_AGG(CONCAT('[year',[n],']'),',') 
                      FROM (SELECT DISTINCT 
                                   ROW_NUMBER() OVER 
                                   (PARTITION BY LEFT([value], 7) ORDER BY [value]) AS [n] 
                              FROM [admin] ) q );
      SET  @query = 
       N'SELECT *
           FROM
           (
            SELECT DISTINCT LEFT([value], 7) AS version, RIGHT([value], 4) AS year,
                   CONCAT(''year'',ROW_NUMBER() OVER 
                                   (PARTITION BY LEFT([value], 7) 
                                        ORDER BY RIGHT([value], 4))) AS [n]
              FROM [admin]
             WHERE [key] LIKE ''%VERSION%'' ) q
          PIVOT (
                 MAX([year]) FOR [n] IN (' + @cols + N')
                ) p
          ORDER BY [version]';
      
      EXEC sp_executesql @query; 
      

      Demo

      顺便说一句,您还可以将value 拆分为@ 符号SUBSTRING([value],1,CHARINDEX('@',[value])-1) 以提取versionSUBSTRING([value],CHARINDEX('@',[value])+1,LEN([value])) 以提取year 列而不将长度值指定为函数中的参数作为替代。

      【讨论】:

        猜你喜欢
        • 2015-08-14
        • 2021-11-17
        • 1970-01-01
        • 2012-05-12
        • 1970-01-01
        • 1970-01-01
        • 2012-08-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多