如何在SQL Server中聚合未知数量的列而不聚合?

Zul*_*u Z 4 sql-server pivot sql-server-2012

我有查询返回客户贷款与相关的抵押品名称,如下面(1)但我想连续只有一个不同的贷款编号和旁边的名称,如同其他例子(2).一直在玩旋转,但无法解决,因为我没有汇总列,我不知道有多少贷款数字,我将得到每笔贷款可能有多少抵押品.怎么做???可能在SQL Server 2012中?

谢谢

(1)

loanid|name  |Address |
1     |John  |New York|
1     |Carl  |New York|
1     |Henry |Boston  |
2     |Robert|Chicago |
3     |Joanne|LA      |
3     |Chris |LA      |
Run Code Online (Sandbox Code Playgroud)

(2)我需要这样的东西

loanid|name  |address  |name |address |name|address|
1     |Jonh  |New York |Carl |New York|Henry|Boston|
2     |Robert|Chicago  |
3     |Joanne|LA       |Chris|LA|
Run Code Online (Sandbox Code Playgroud)

Tar*_*ryn 13

虽然M.Ali的答案可以为您提供结果,但由于您使用的是SQL Server 2012,我会将这些nameaddress列略有不同以获得最终结果.

由于您使用的是SQL Server 2012,因此可以使用CROSS APPLYwith VALUES将这些多列拆分为多行.但在你这样做之前,我会用你row_number()来获得你将拥有的新列的总数.

使用CROSS APPLY"UNPIVOT"数据的代码如下所示:

select d.loanid, 
  col = c.col + cast(seq as varchar(10)),
  c.value
from
(
  select loanid, name, address,
    row_number() over(partition by loanid
                      order by loanid) seq
  from yourtable
) d
cross apply
(
  values
    ('name', name),
    ('address', address)
) c(col, value);
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.这将使您的数据格式类似于:

| LOANID |      COL |    VALUE |
|--------|----------|----------|
|      1 |    name1 |     John |
|      1 | address1 | New York |
|      1 |    name2 |     Carl |
|      1 | address2 | New York |
|      1 |    name3 |    Henry |
|      1 | address3 |   Boston |
Run Code Online (Sandbox Code Playgroud)

您现在拥有一个COL包含所有新列名称的列,并且关联的值也位于单个列中.现在,新列名称的末尾有一个数字(1,2,3等),具体取决于每个条目的总条目数loanid.现在你可以申请PIVOT:

select loanid,
  name1, address1, name2, address2,
  name3, address3
from
(
  select d.loanid, 
    col = c.col + cast(seq as varchar(10)),
    c.value
  from
  (
    select loanid, name, address,
      row_number() over(partition by loanid
                        order by loanid) seq
    from yourtable
  ) d
  cross apply
  (
    values
      ('name', name),
      ('address', address)
  ) c(col, value)
) src
pivot
(
  max(value)
  for col in (name1, address1, name2, address2,
              name3, address3)
) piv;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.最后,如果你不知道有多少对NameAddress你将有那么你可以使用动态SQL:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(col+cast(seq as varchar(10))) 
                    from 
                    (
                      select row_number() over(partition by loanid
                                                order by loanid) seq
                      from yourtable
                    ) d
                    cross apply
                    (
                      select 'Name', 1 union all
                      select 'Address', 2
                    ) c (col, so)
                    group by seq, col, so
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT loanid,' + @cols + ' 
            from 
            (
              select d.loanid, 
                col = c.col + cast(seq as varchar(10)),
                c.value
              from
              (
                select loanid, name, address,
                  row_number() over(partition by loanid
                                    order by loanid) seq
                from yourtable
              ) d
              cross apply
              (
                values
                  (''name'', name),
                  (''address'', address)
              ) c(col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

exec sp_executesql @query;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.两个版本都给出了结果:

| LOANID |  NAME1 | ADDRESS1 |  NAME2 | ADDRESS2 |  NAME3 | ADDRESS3 |
|--------|--------|----------|--------|----------|--------|----------|
|      1 |   John | New York |   Carl | New York |  Henry |   Boston |
|      2 | Robert |  Chicago | (null) |   (null) | (null) |   (null) |
|      3 | Joanne |       LA |  Chris |       LA | (null) |   (null) |
Run Code Online (Sandbox Code Playgroud)

  • @ZuluZ有两个问题.什么太复杂了?我认为这是TLDR的简称,非常难过.2:有人已经为你完成了所有的工作,以及为什么这样做有一些非常详细的解释,这有多复杂. (5认同)

M.A*_*Ali 7

测试数据

DECLARE @TABLE TABLE (loanid INT,name VARCHAR(20),[Address] VARCHAR(20))
INSERT INTO @TABLE VALUES
(1,'John','New York'),(1,'Carl','New York'),(1,'Henry','Boston'),
(2,'Robert','Chicago'),(3,'Joanne','LA'),(3,'Chris','LA')
Run Code Online (Sandbox Code Playgroud)

询问

SELECT  loanid
       ,ISNULL(name1, '')    AS name1
       ,ISNULL(Address1, '') AS Address1
       ,ISNULL(name2, '')    AS name2
       ,ISNULL(Address2, '') AS Address2
       ,ISNULL(name3, '')    AS name3
       ,ISNULL(Address3, '') AS Address3
FROM (
SELECT loanid
      ,'name' + CAST(ROW_NUMBER() OVER (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) AS Cols
      , name AS Vals
FROM @TABLE
UNION ALL
SELECT loanid
      ,'Address' + CAST(ROW_NUMBER() OVER (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) 
      , [Address] 
FROM @TABLE ) t
 PIVOT (MAX(Vals)
        FOR Cols 
        IN (name1, Address1,name2,Address2,name3,Address3)
        )P
Run Code Online (Sandbox Code Playgroud)

结果集

????????????????????????????????????????????????????????????????????
? loanid ? name1  ? Address1 ? name2 ? Address2 ? name3 ? Address3 ?
????????????????????????????????????????????????????????????????????
?      1 ? John   ? New York ? Carl  ? New York ? Henry ? Boston   ?
?      2 ? Robert ? Chicago  ?       ?          ?       ?          ?
?      3 ? Joanne ? LA       ? Chris ? LA       ?       ?          ?
????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

动态列的更新

DECLARE @Cols NVARCHAR(MAX);

SELECT @Cols =  STUFF((
                    SELECT DISTINCT ', ' +  QUOTENAME(Cols)
                    FROM (
                    SELECT loanid
                          ,'name' + CAST(ROW_NUMBER() OVER (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) AS Cols
                          , name AS Vals
                    FROM @TABLE
                    UNION ALL
                    SELECT loanid
                          ,'Address' + CAST(ROW_NUMBER() OVER (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) 
                          , [Address] 
                    FROM @TABLE ) t
                    GROUP BY QUOTENAME(Cols)
                    FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,'')


DECLARE @Sql NVARCHAR(MAX);

SET @Sql  = 'SELECT ' + @Cols +   '
            FROM (
            SELECT loanid
                  ,''name'' + CAST(ROW_NUMBER() OVER 
                            (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) AS Cols
                  , name AS Vals
            FROM @TABLE
            UNION ALL
            SELECT loanid
                  ,''Address'' + CAST(ROW_NUMBER() OVER 
                                (PARTITION BY loanid ORDER BY loanid)  AS NVARCHAR(10)) 
                  , [Address] 
            FROM @TABLE ) t
             PIVOT (MAX(Vals)
                    FOR Cols 
                    IN (' + @Cols + ')
                    )P'

EXECUTE sp_executesql @Sql
Run Code Online (Sandbox Code Playgroud)

注意

这对我的答案中的给定样本数据无效,因为它使用表变量,因为它有自己的范围,所以它对动态sql不可见.但是这个解决方案可以在普通的sql server表上运行.

选择列的顺序也会略有不同.

  • 如果你真的想学习一些很酷的枢轴技术,请查找一个名为Bluefeet的用户,查看该用户对问题的回答,你会学到很多东西.:) (2认同)