【问题标题】:T-SQL dynamic pivotT-SQL 动态数据透视
【发布时间】:2012-08-25 23:55:37
【问题描述】:

好的,我有一张像这样的表

ItemID | ColumnName | Value
1      | name       | Peter
1      | phone      | 12345678
1      | email      | peter@host.com
2      | name       | John
2      | phone      | 87654321
2      | email      | john@host.com
3      | name       | Sarah
3      | phone      | 55667788
3      | email      | sarah@host.com

现在我需要把它变成这样:

ItemID | name  | phone    | email
1      | Peter | 12345678 | peter@host.com
2      | John  | 87654321 | john@host.com
3      | Sarah | 55667788 | sarah@host.com

我一直在查看动态枢轴示例,但似乎无法将它们融入我的场景。

谁能帮忙?

【问题讨论】:

  • 我在您的数据中看不到数据透视。您在第一个块中以一种奇怪的方式列出了常规列名和值,通常在第二个块中。
  • 如果第一个块代表您的实际数据,那么为什么它会像这样存储而不是标准化?
  • 为什么需要动态 PIVOT 来处理这些数据?这可以通过静态 PIVOT 来实现(检查我的答案)。是因为您希望 ColumnName 的值不是姓名、电话和电子邮件吗?
  • 是的,列名和列数会改变。我应该提到这一点。
  • 数据未标准化的相同原因。

标签: sql sql-server tsql dynamic pivot


【解决方案1】:

看看下面的例子

CREATE TABLE #Table (
        ID INT,
        ColumnName VARCHAR(250),
        Value VARCHAR(250)
)

INSERT INTO #Table SELECT 1,'name','Peter' 
INSERT INTO #Table SELECT 1,'phone','12345678' 
INSERT INTO #Table SELECT 1,'email','peter@host.com' 
INSERT INTO #Table SELECT 2,'name','John' 
INSERT INTO #Table SELECT 2,'phone','87654321' 
INSERT INTO #Table SELECT 2,'email','john@host.com' 
INSERT INTO #Table SELECT 3,'name','Sarah' 
INSERT INTO #Table SELECT 3,'phone','55667788' 
INSERT INTO #Table SELECT 3,'email','sarah@host.com' 

---I assumed your tablename as TESTTABLE--- 
DECLARE @cols NVARCHAR(2000) 
DECLARE @query NVARCHAR(4000) 

SELECT  @cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT 
                                '],[' + t.ColumnName 
                        FROM    #Table AS t 
                        --ORDER BY '],[' + t.ID 
                        FOR XML PATH('') 
                      ), 1, 2, '') + ']' 

SELECT  @cols

SET @query = N'SELECT ID,'+ @cols +' FROM 
(SELECT t1.ID,t1.ColumnName , t1.Value FROM #Table AS t1) p 
PIVOT (MAX([Value]) FOR ColumnName IN ( '+ @cols +' )) 
AS pvt;' 

EXECUTE(@query)

DROP TABLE #Table

【讨论】:

  • 非常感谢,这正是我想要的!
【解决方案2】:

试试这个:

SQL Server 2005+

 ;with 
        cte_name  as(select * from <table> where ColumnName='name'),
        cte_phone as(select * from <table> where ColumnName='phone'),
        cte_email as(select * from <table> where ColumnName='email')
  select n.ItemID,n.Value [Name],p.Value [Phone],e.Value [Email] 
  from  cte_name n
  join  cte_phone p
  on    n.ItemID=p.ItemID
  join  cte_email e
  on    n.ItemID=e.ItemID


SQL Fiddle Demo

【讨论】:

    【解决方案3】:

    您不需要动态数据透视表,因为它将是一张不同的表格。只需执行以下操作:

    name    phone   email
    ---------------------------------
    Peter            
            123456
                     peter@host.com
    

    查看SQL fiddle

    SELECT DISTINCT u.ItemID, n.Value as 'name', p.Value as 'phone', e.Value as 'email'
    FROM UserData u
    INNER JOIN(
    SELECT ItemID, Value 
    FROM UserData WHERE ColumnName = 'name') n ON n.ItemID = u.ItemID
    INNER JOIN(
    SELECT ItemID, Value 
    FROM UserData WHERE ColumnName = 'phone') p ON p.ItemID = u.ItemID
    INNER JOIN(
    SELECT ItemID, Value 
    FROM UserData WHERE ColumnName = 'email') e ON e.ItemID = u.ItemID
    

    【讨论】:

    • 问题是 ColumnNames 是动态的。它们的名称和列数都会有所不同。
    【解决方案4】:

    这是我用于联系人列表的查询 :)

    SELECT *
    FROM
        (
        SELECT Contact_Id AS CT
              , [Age]
              , [Sex]
              , [State]
              , [Country]
              , [Keyword]
              , [Married]
              , [Kids]
              , [Car]
         FROM
             (SELECT c.PropertyName
                   , c.ValueString
                   , c.Contact_Id
              FROM
                  ContactProfiles c) AS ctp
             PIVOT (max(ctp.ValueString) FOR PropertyName IN ([Age], [Sex], [State], [Country], [Keyword], [Married], [Kids], [Car])) AS PivotTable
             ) AS pvt
    
    WHERE
        pvt.[Age] > 18
        AND (pvt.[State] = 'CA' OR pvt.[State] = 'NY')
        AND pvt.[Sex] = 'F'
        --*AND pvt.[Keyword] LIKE '%B;%'
        AND pvt.[Married] = 'True'
        AND pvt.[Kids] > 0
    

    【讨论】:

      【解决方案5】:

      你试过了吗:

      SELECT ItemID, name, phone, email
      FROM
      (SELECT [ItemID] ,[ColumnName] ,[Value] FROM Item) Item
      PIVOT (MAX(Value) FOR ColumnName IN (name, phone, email) ) as pvt 
      

      【讨论】:

      • 问题是 ColumnNames 是动态的。它们的名称和列数都会有所不同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 2014-10-16
      • 2010-12-28
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多