Sql server 如何在MSSQL查询中聚合字符串数据类型

Sql server 如何在MSSQL查询中聚合字符串数据类型,sql-server,Sql Server,我有如下的SQL表 需要以以下任一格式查询数据。请帮助我构建MS SQL查询,以获得所需格式的结果 下面是创建表/插入记录的SQL脚本 create table Table1 (ID varchar(50),Col1 varchar(50),Col2 varchar(50),Col3 varchar(50),Col4 varchar(50),Col5 varchar(50),Col6 varchar(50)) go insert into Table1 select '1-117D'

我有如下的SQL表

需要以以下任一格式查询数据。请帮助我构建MS SQL查询,以获得所需格式的结果

下面是创建表/插入记录的SQL脚本

    create table Table1 (ID varchar(50),Col1 varchar(50),Col2 varchar(50),Col3 varchar(50),Col4 varchar(50),Col5 varchar(50),Col6 varchar(50))
go
insert into Table1
select '1-117D',null,null,'DDDD',null,null,'DDDD@emailid.com' union all 
select '1-117D',null,'CCCC',null,null,'CCCC@emailid.com',null union all 
select '1-117D','AAAA',null,null,'AAAA@emailid.com',null,null union all 
select '1-117D','BBBB',null,null,'BBBB@emailid.com',null,null 
go
select * from Table1
这确实很难看,但它是基于我们拥有的样本数据工作的

WITH RNs AS(
    SELECT T1.ID,
           T1.Col1,
           T1.Col2,
           T1.Col3,
           T1.Col4,
           T1.Col5,
           T1.Col6,
           CASE WHEN T1.Col1 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col1 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col1) END AS Col1RN,
           CASE WHEN T1.Col2 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col2 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col2) END AS Col2RN,
           CASE WHEN T1.Col3 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col3 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col3) END AS Col3RN,
           CASE WHEN T1.Col4 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col4 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col4) END AS Col4RN,
           CASE WHEN T1.Col5 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col5 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col5) END AS Col5RN,
           CASE WHEN T1.Col6 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col6 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col6) END AS Col6RN
    FROM dbo.Table1 T1)
SELECT R.ID,
       MAX(Col1) AS Col1,
       MAX(Col2) AS Col2,
       MAX(Col3) AS Col3,
       MAX(Col4) AS Col4,
       MAX(Col5) AS Col1,
       MAX(Col6) AS Col6
FROM RNs R
GROUP BY R.ID,
         COALESCE(R.Col1RN, R.Col2RN, R.Col3RN),
         COALESCE(R.Col4RN, R.Col5RN, R.Col6RN);
不过,正如我在评论中提到的,您提供的数据表明您存在一些重大的非规范化问题,您应该努力解决这些问题。例如,如果第1-3列表示一个名称,第4-6列表示一封电子邮件,那么应该只有2列,一个名称列和一封电子邮件列(可能还有某种进一步的ID)。当然不是3,列中的
NULL
值未完成,当“用完”列时,再次开始重用它

不幸的是,没有足够的信息让我正确猜测数据的真实外观(例如,没有名称的列意味着我不知道它们是否表示相同的内容)。无论如何,我会考虑退后一步,重新考虑一下你的设计。

< P>这真的很难看,但是它是基于我们的样本数据。

WITH RNs AS(
    SELECT T1.ID,
           T1.Col1,
           T1.Col2,
           T1.Col3,
           T1.Col4,
           T1.Col5,
           T1.Col6,
           CASE WHEN T1.Col1 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col1 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col1) END AS Col1RN,
           CASE WHEN T1.Col2 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col2 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col2) END AS Col2RN,
           CASE WHEN T1.Col3 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col3 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col3) END AS Col3RN,
           CASE WHEN T1.Col4 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col4 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col4) END AS Col4RN,
           CASE WHEN T1.Col5 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col5 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col5) END AS Col5RN,
           CASE WHEN T1.Col6 IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY T1.ID, CASE WHEN T1.Col6 IS NOT NULL THEN 0 ELSE 1 END ORDER BY T1.Col6) END AS Col6RN
    FROM dbo.Table1 T1)
SELECT R.ID,
       MAX(Col1) AS Col1,
       MAX(Col2) AS Col2,
       MAX(Col3) AS Col3,
       MAX(Col4) AS Col4,
       MAX(Col5) AS Col1,
       MAX(Col6) AS Col6
FROM RNs R
GROUP BY R.ID,
         COALESCE(R.Col1RN, R.Col2RN, R.Col3RN),
         COALESCE(R.Col4RN, R.Col5RN, R.Col6RN);
不过,正如我在评论中提到的,您提供的数据表明您存在一些重大的非规范化问题,您应该努力解决这些问题。例如,如果第1-3列表示一个名称,第4-6列表示一封电子邮件,那么应该只有2列,一个名称列和一封电子邮件列(可能还有某种进一步的ID)。当然不是3,列中的
NULL
值未完成,当“用完”列时,再次开始重用它


不幸的是,没有足够的信息让我正确猜测数据的真实外观(例如,没有名称的列意味着我不知道它们是否表示相同的内容)。无论如何,我会考虑退一步,重新考虑一下你的设计。

< P>我也想重申一个事实,你可能想把你的数据结构从水平格式规范到垂直格式,以允许数据缩放。

但在反馈之外,您可以尝试这样做,以获得结果集1中显示的内容。您需要对剩余的数据集进行测试,以确保这是您希望代码执行的操作

IF OBJECT_ID(N'tempdb..#t') IS NOT NULL DROP TABLE #t
CREATE TABLE #t (ID varchar(50),Col1 varchar(50),Col2 varchar(50),Col3 varchar(50),Col4 varchar(50),Col5 varchar(50),Col6 varchar(50))

GO

INSERT INTO #t
SELECT '1-117D',NULL,NULL,'DDDD',NULL,NULL,'DDDD@emailid.com' UNION ALL 
SELECT '1-117D',NULL,'CCCC',NULL,NULL,'CCCC@emailid.com',NULL UNION ALL 
SELECT '1-117D','AAAA',NULL,NULL,'AAAA@emailid.com',NULL,NULL UNION ALL 
SELECT '1-117D','BBBB',NULL,NULL,'BBBB@emailid.com',NULL,NULL 

GO

;WITH n1 AS (
    SELECT
        ID,--Columns that are the same for each row
        Col1,Col2,Col3,Col4,Col5,Col6
    FROM #t AS t
),
n2 AS (
SELECT ID,FieldName,Value, ROW_NUMBER() OVER (PARTITION BY ID,FieldName ORDER BY Value) AS RowNumber
FROM n1
UNPIVOT ( Value FOR FieldName IN (Col1,Col2,Col3,Col4,Col5,Col6) ) AS pvt1
)
SELECT ID,Col1,Col2,Col3,Col4,Col5,Col6
FROM n2
PIVOT (
    MAX(Value) 
    FOR FieldName IN (
        Col1,Col2,Col3,Col4,Col5,Col6
        )
) AS pivot_table;

GO

DROP TABLE #t

我还要重申一个事实,即您可能希望将数据结构从水平格式规范化为垂直格式,以允许数据缩放

但在反馈之外,您可以尝试这样做,以获得结果集1中显示的内容。您需要对剩余的数据集进行测试,以确保这是您希望代码执行的操作

IF OBJECT_ID(N'tempdb..#t') IS NOT NULL DROP TABLE #t
CREATE TABLE #t (ID varchar(50),Col1 varchar(50),Col2 varchar(50),Col3 varchar(50),Col4 varchar(50),Col5 varchar(50),Col6 varchar(50))

GO

INSERT INTO #t
SELECT '1-117D',NULL,NULL,'DDDD',NULL,NULL,'DDDD@emailid.com' UNION ALL 
SELECT '1-117D',NULL,'CCCC',NULL,NULL,'CCCC@emailid.com',NULL UNION ALL 
SELECT '1-117D','AAAA',NULL,NULL,'AAAA@emailid.com',NULL,NULL UNION ALL 
SELECT '1-117D','BBBB',NULL,NULL,'BBBB@emailid.com',NULL,NULL 

GO

;WITH n1 AS (
    SELECT
        ID,--Columns that are the same for each row
        Col1,Col2,Col3,Col4,Col5,Col6
    FROM #t AS t
),
n2 AS (
SELECT ID,FieldName,Value, ROW_NUMBER() OVER (PARTITION BY ID,FieldName ORDER BY Value) AS RowNumber
FROM n1
UNPIVOT ( Value FOR FieldName IN (Col1,Col2,Col3,Col4,Col5,Col6) ) AS pvt1
)
SELECT ID,Col1,Col2,Col3,Col4,Col5,Col6
FROM n2
PIVOT (
    MAX(Value) 
    FOR FieldName IN (
        Col1,Col2,Col3,Col4,Col5,Col6
        )
) AS pivot_table;

GO

DROP TABLE #t

字符串的聚合方式与任何其他数据类型的聚合方式相同(除此之外,您不能对其应用诸如
SUM
AVG
之类的数值聚合)。看起来您需要
MAX
。你尝试了什么,为什么没有成功?如果我尝试了,我会错过Col1=bbbbbb记录,但我需要它。是的,现在我再次查看,你的数据看起来真的去噪了。我建议将其正常化;你将来会过得轻松得多。或者我们缺少了一些东西(比如真正有意义的列名)。例如,什么链接
DDDD@emailid.com
'AAAA@emailid.com“
而不是
”BBBB@emailid.com
?字符串的聚合方式与任何其他数据类型的聚合方式相同(除此之外,您不能对其应用诸如
SUM
AVG
之类的数值聚合)。看起来您需要
MAX
。你尝试了什么,为什么没有成功?如果我尝试了,我会错过Col1=bbbbbb记录,但我需要它。是的,现在我再次查看,你的数据看起来真的去噪了。我建议将其正常化;你将来会过得轻松得多。或者我们缺少了一些东西(比如真正有意义的列名)。例如,什么链接
DDDD@emailid.com
'AAAA@emailid.com“
而不是
”BBBB@emailid.com
?非常有趣的解决方案。我很难理解这个逻辑,但我想我是在做了一些测试来理解它之后得到的。以前从未使用过
第一个值
最后一个值
。测试表明,
LAST_VALUE
只返回数据集的当前最后值(或者实际上是它本身),除非在无界前后行之间添加一个附加子句
)。@JoeFletch…最初我尝试了完全相同的方法(unpv piv):),但我假设这可能不是op想要的,测试同一col1的不同条目后,例如(..'AAAA',NULL,NULL,'AAAA@emailid.com“…”(…'AAAA',空,空,'XYZ@emailid.com'..). 答案中的第一个值不是“正确的”,因为它可能会混淆行,例如col1:A,col4:Z,所有其他空值,col4将不会被拾取……更好的方法可能是在一个行标识符
的情况下排序,当ColX为null时,则为1,否则为0 end,rowid\u pk\u或_2;,ColX
:拾取第一个非空值(如果行是对称的,col1&colX不为null..那么它可能会按预期工作).至于窗口框架,请查看:非常有趣的解决方案。我很难遵循逻辑,但我认为我在做了一些测试以理解之后现在得到了它。以前从未使用过
FIRST\u VALUE
LAST\u VALUE
。测试表明
LAST\u VALUE
仅返回数据集当前的LAST VALUE(或者实际上是它本身)除非你在无界的前面和无界的后面之间添加一个额外的子句
()。@JoeFletch…起初我尝试了完全相同的方法(unpv piv):),但我认为这可能不是op想要的,在测试了相同col1的不同条目之后,例如(..'AAAA',NULL,NULL,'AAAA@emailid.com'..),(..'AAAA',空,空,'XYZ@emailid.com“..)。第一个_值,如答案中所示,不是“正确的”,因为它可能会混淆行,例如col