【问题标题】:SQL Server : fastest way to change rows to columnsSQL Server:将行更改为列的最快​​方法
【发布时间】:2021-09-03 12:43:38
【问题描述】:

我的数据库中有两个表存在以下问题:

COMMENT

KEY 
TYPE
NUMBER
TEXT

(KEY, TYPE, NUMBER)组成的复合键

RESULTS

KEY
TYPE1
TYPE2
...
TYPE20
TEXT1
TEXT2
...
TEXT20

COMMENT 表的示例如下:

KEY | TYPE | NUMBER | TEXT|
1      A     0001     SAMPLETEXT
1      A     0002     SAMPLETEXT2
1      B     0001     SAMPLETEXT3
1      B     0002     SAMPLETEXT4
1      B     0003     SAMPLETEXT5
2      C     0001     SAMPLETEXT6
2      C     0002     SAMPLETEXT7
3      A     0001     SAMPLETEXT8

对于每个 KEY,只有 3 种不同的类型 A,B,C,而一个 TYPENUMBER 字段中最多可以有 0020。这些记录按 KEY 然后按 TYPE

排序

我需要完成以下操作:对于 COMMENT 表中的每个 KEY,将前 20 TYPE 行插入到 de RESULTS 表内的每一列中(TYPE1 Comment 表中的第一种类型,TYPE2 用于注释表中的第二种类型,依此类推)并将前 20 个 TEXT 行插入 RESULTS 表中的每一列(TEXT1 用于第一个文本,TEXT2 用于第二个文本等等)

RESULTS 表如下所示:

KEY | TYPE1 | TYPE2 | TYPE3 | ... | TYPE20 | TEXT1 | TEXT2 | ... | TEXT20
1      A        A      B             NULL    SAMPTE1 SAMPTE2       NULL
2      C        C      NULL          NULL    SAMPTE6 SAMPTE7       NULL
3      A     NULL      NULL  ...    NULL     SAMPTE7 NULL    ....  NULL

RESULTS 表的每个 KEY 都有一行,最多 20 个 TEXT 字段及其对应的类型。

如您所见,这个RESULTS 表显然设计不佳。它是 70 年代制作的,我们无法更改。

实施时可能会出现一些问题,以下是答案:

  1. 如果一个KEYCOMMENT表中有超过20个TEXT怎么办?我们不在乎,我们只插入前 20 个
  2. 例如,如果我有 23 个 A 类文本和 10 个 B 类文本怎么办?然后只有前 20 个 A 型文本会出现在 RESULTS
  3. 有什么办法可以更改RESULTS 表吗?很遗憾,没有。
  4. TYPE1是否匹配RESULTS表中的TEXT1TYPE2是否匹配TEXT2等等?是的,匹配的列数也是一样的。
  5. 如果COMMENT表中的TEXT少于20个,RESULTS中TEXTTYPE的其余值是否为空?是的

问题是,什么是最简洁、最快、可扩展、不乏味的实现方式?

另外,如何实现它,以便将来 RESULTS 表可以有 N 更多 TYPE 列和 N 更多 TEXT 列?

我听说过使用 PIVOT 表、连接和许多其他技术,但我不知道如何实现。

【问题讨论】:

  • 嗨,也许你可以pivot
  • 您没有解决的一个问题是为什么要在 SQL 中执行此操作。这是一个清晰的 SQL 反模式/代码气味。如果是为了演示,在数据库中做这个是错误的位置,如果是为了进一步的SQL处理或存储,这是一个糟糕的结构; SQL(语言)和 RDBMS 都是为您开始使用的结构明确设计的。

标签: sql join sql-server-2012 pivot exists


【解决方案1】:

您可以在 T-SQL 文档中阅读有关 pivot 操作的所有信息。您的答案需要双轴:一次为每个[Key,Number] 组合旋转Type,一次为每个[Key,Number] 组合旋转Text

为了避免Key 列上的额外聚合,您可以将这两个透视操作拆分为单独的子查询。下面的解决方案将这两个枢轴子查询放在名为piv1piv2 的两个common table expressions(CTE)中。请注意,每个子查询仅从输出所需的那些列开始。此列过滤是通过一个名为 comm 的附加子查询完成的。

最终查询 joins piv1piv2 在它们的共同 Key 列和 inserts 预定义 Result 表中的输出。

N TypeText 列的非繁琐方式将需要动态 SQL。 虽然这样的解决方案并不乏味,但它也非常重要!如果您对 joinpivot 等概念仍然不熟悉,那么我强烈建议您不要这样做暂时的路线。复制粘贴一些列名将比开发和维护动态 SQL 查询快得多。

样本数据

create table Comment
(
  [Key] int,
  [Type] nvarchar(1),
  [Number] nvarchar(4), --> changing to numeric type will drop the leading zeros
  [Text] nvarchar(20)
)

insert into Comment ([Key], [Type], [Number], [Text]) values
(1, 'A', '0001', 'SAMPLETEXT'),
(1, 'A', '0002', 'SAMPLETEXT2'),
(1, 'B', '0001', 'SAMPLETEXT3'),
(1, 'B', '0002', 'SAMPLETEXT4'),
(1, 'B', '0003', 'SAMPLETEXT5'),
(2, 'C', '0001', 'SAMPLETEXT6'),
(2, 'C', '0002', 'SAMPLETEXT7'),
(3, 'A', '0001', 'SAMPLETEXT8');

create table Result
(
  [Key] int,
  [Type1] nvarchar(1),
  [Type2] nvarchar(1),
  [Type3] nvarchar(1),
  -- repeat for [Type4] to [Type19]
  [Type20] nvarchar(1),
  [Text1] nvarchar(20),
  [Text2] nvarchar(20),
  [Text3] nvarchar(20),
  -- repeat for [Text4] to [Text19]
  [Text20] nvarchar(20)
);

解决方案

在单独的 CTE 中组合双 pivot,在单个查询语句中组合 joininsert 操作。

with piv1 as
(
  select piv.[Key] as [Key],
         piv.[0001] as [Type1],
         piv.[0002] as [Type2],
         piv.[0003] as [Type3],
         -- repeat for [Type4] to [Type19]
         piv.[0020] as [Type20]
  from ( select c.[Key], c.[Type], c.[Number] from comment as c ) as comm
  pivot (min(comm.[Type]) for comm.[Number] in ([0001], [0002], [0003], [0020])) piv -- add values [0004] to [0019]
),
piv2 as
(
  select piv.[Key] as [Key],
         piv.[0001] as [Text1],
         piv.[0002] as [Text2],
         piv.[0003] as [Text3],
         -- repeat for [Text4] to [Text19]
         piv.[0020] as [Text20]
  from ( select c.[Key], c.[Text], c.[Number] from comment as c ) as comm
  pivot (min(comm.[Text]) for comm.[Number] in ([0001], [0002], [0003], [0020])) piv -- add values [0004] to [0019]
)
insert into Result ([Key],
                    [Type1], [Type2], [Type3], [Type20], -- add columns [Type4] to [Type19]
                    [Text1], [Text2], [Text3], [Text20]) -- add columns [Text4] to [Text19]
select piv1.[Key],
       piv1.[Type1], piv1.[Type2], piv1.[Type3], piv1.[Type20], -- add columns piv1.[Type4] to piv1.[Type19]
       piv2.[Text1], piv2.[Text2], piv2.[Text3], piv2.[Text20]  -- add columns piv2.[Text4] to piv2.[Text19]
from piv1
join piv2 on piv2.[Key] = piv1.[Key];

结果

Key  Type1  Type2  Type3  Type20  Text1        Text2        Text3        Text20
---  -----  -----  -----  ------  -----------  -----------  -----------  -----------
1    A      A      B      null    SAMPLETEXT   SAMPLETEXT2  SAMPLETEXT5  null
2    C      C      null   null    SAMPLETEXT6  SAMPLETEXT7  null         null
3    A      null   null   null    SAMPLETEXT8  null         null         null

Fiddle 了解实际情况。

【讨论】:

  • 这是迄今为止我一直在寻找的最佳答案!非常感谢
猜你喜欢
  • 2011-02-21
  • 2012-01-23
  • 1970-01-01
  • 2010-10-13
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
相关资源
最近更新 更多