2014-03-31 16 views
3

我有一个查询返回客户贷款与像下面(1) 相关的抵押品名称,但我想只有一个不同的贷款号码在一行和旁边的名称旁边像其他示例(2)。一直玩pivoting,但无法弄清楚,因为我没有聚合列,我不知道有多少贷款数字,我将得到多少抵押品每个贷款可能有。怎么做???可能在SQL Server 2012中?如何在SQL Server中调整未知数量的列和不聚合?

感谢

(1)

loanid|name |Address | 
1  |John |New York| 
1  |Carl |New York| 
1  |Henry |Boston | 
2  |Robert|Chicago | 
3  |Joanne|LA  | 
3  |Chris |LA  | 

(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| 
+0

是否每个'name' /'地址'都需要是单独的列吗?它们可以是一列中的逗号分隔列表吗?你还使用了什么RDBMS? – Brad

+0

布拉德,我已经提到它 - SQL Server 2012.名称/地址可以用逗号分隔。 –

+0

http://stackoverflow.com/questions/5196371/sql-query-concatenating-results-into-one-string – Brad

回答

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') 

查询

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 

结果集

╔════════╦════════╦══════════╦═══════╦══════════╦═══════╦══════════╗ 
║ loanid ║ name1 ║ Address1 ║ name2 ║ Address2 ║ name3 ║ Address3 ║ 
╠════════╬════════╬══════════╬═══════╬══════════╬═══════╬══════════╣ 
║  1 ║ John ║ New York ║ Carl ║ New York ║ Henry ║ Boston ║ 
║  2 ║ Robert ║ Chicago ║  ║   ║  ║   ║ 
║  3 ║ Joanne ║ LA  ║ Chris ║ LA  ║  ║   ║ 
╚════════╩════════╩══════════╩═══════╩══════════╩═══════╩══════════╝ 

更新动态列

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 

这不适用于我的答案给定的示例数据,因为它使用表变量,并且它对动态sql不可见,因为它有它自己的范围。但是这个解决方案可以在普通的sql server表上工作。

此外,列的选择顺序稍有不同。

+0

这适用于3列,但它必须动态建立以真正有用的“未知列数“ – Brad

+0

多数民众赞成那么不难,要么让我拉你出:) –

+0

@布拉德你不得不问我这没有你,看看现在朋友第二个解决方案是动态的列数。 –

0
SELECT DISTINCT 
     loanid 
     ,STUFF((SELECT DISTINCT ',' + name +' ('+address+')' 
       FROM table a 
       WHERE a.loanid = b.loanid 
       FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'') 

FROM table b 

这将使

loanid | name(address) 
1  | name (address),name2 (address2),name3........ 
2  | name (address),name2 (address2),name3........ 
3  | name (address),name2 (address2),name3........ 
12

虽然M.Ali's answer将让你的结果,因为你使用的是SQL Server 2012中我会逆转置的nameaddress柱略有不同,以获得最终结果。

由于您使用的是SQL Server 2012,因此您可以使用CROSS APPLYVALUES将这些多列反转为多行。但在你这样做之前,我会用row_number()来得到新的列的总数。

代码为 “UNPIVOT” 数据使用CROSS APPLY的样子:

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); 

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 | 

你现在有一列COL与所有新的列名和关联的值也是一列。根据每个loanid有多少个总条目,新列名现在在最后有一个数字(1,2,3等)。现在您可以套用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; 

请参阅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; 

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) | 
+0

谢谢,但它看起来太复杂了。虽然会检查这些交叉应用。 –

+4

@ZuluZ两个问题。 1.什么太复杂了?我认为这是TLDR的简称,这很令人伤心。 2:有人已经为你做了所有的工作,以及为什么会这样工作的一些非常详细的解释,这是多么复杂。 – Zane