SQL Pivot 和 Distinct from new Columns

Posted

技术标签:

【中文标题】SQL Pivot 和 Distinct from new Columns【英文标题】:SQL Pivot and 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

【问题讨论】:

【参考方案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 列而不将长度值指定为函数中的参数作为替代。

【讨论】:

以上是关于SQL Pivot 和 Distinct from new Columns的主要内容,如果未能解决你的问题,请参考以下文章

SQL Pivot Table w/ and w/o Distinct Same Result

在 Snowflake 中使用 Count Distinct 和 Pivot

Sql PIVOT,如何使用 PIVOT 将结果中的 NULL 转换为值 0

SQL中 oderby和distinct哪一个先执行

PIVOT SQL - 指导

关于SQL的distinct 用法