SQL转换值以11行返回到总共89列

时间:2012-09-23 16:10:11

标签: sql sql-server pivot

我需要一些帮助才能将数据行转换为列。

我的每一行都包含8列,我希望所有这些列都包含在最终的列列表中。

通常情况下,我会编写一个类似下面的选择语句来返回与特定ProductID

相关的所有定价行(大约11个)
SELECT  
    ProductID,
    PricingID, 
    COSBeginQty ,
    COSCOLCode,
    COSTrade,
    COSTypeOfPrice,
    COSIsActive, 
    COSPrice,
    COSPriceTAG,
    RowIndex
FROM 
    Pricing
Where 
    ProductID = XXXXX

我返回的每一行都有关于我想要显示所有返回值的信息:

ProductID, 
CosBeginQty1 COSBeginQty1  COSCOLCode1 COSTrade1 COSTypeOfPrice1 COSIsActive1 COSPrice1 COSPriceTAG1  
CosBeginQty2 COSBeginQty2  COSCOLCode2 COSTrade2 COSTypeOfPrice2 COSIsActive2 COSPrice2 COSPriceTAG2  
CosBeginQty3, COSBeginQty3  COSCOLCode3 COSTrade3 COSTypeOfPrice3 COSIsActive3 COSPrice3 COSPriceTAG3   . . . . 

。 。 。(计算我需要的所有11行,总共89行)列

以下是我表格中的剧本

CREATE TABLE [dbo].[Pricing](
    [ProductID] [uniqueidentifier] NOT NULL,
    [PricingID] [uniqueidentifier] NULL,
    [COSBeginQty] [int] NULL,
    [COSCOLCode] [nvarchar](50) NULL,
    [COSTrade] [nvarchar](50) NULL,
    [COSTypeOfPrice] [nchar](10) NULL,
    [COSIsActive] [bit] NULL,
    [COSPrice] [decimal](12, 3) NULL,
    [COSPriceTAG] [uniqueidentifier] NULL,
    [RowIndex] [int] NULL,
    [COSCreateDate] [datetime] NULL,
    [COSLastModifiedDate] [datetime] NULL,
 CONSTRAINT [PK_Pricing] PRIMARY KEY CLUSTERED 
(
    [ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
INSERT [dbo].[Pricing] ([ProductID], [PricingID], [COSBeginQty], [COSCOLCode], [COSTrade], [COSTypeOfPrice], [COSIsActive], [COSPrice], [COSPriceTAG], [RowIndex], [COSCreateDate], [COSLastModifiedDate]) VALUES (N'99533f6e-218f-48ef-bf01-03ea7808f9b1', N'5d8de11a-2399-4c68-87cd-4969827bed27', 7, N'MAN', N'T1', N'B         ', 1, CAST(23.400 AS Decimal(12, 3)), N'bf1d79bf-a60d-4603-8c2d-04492e9e1575', 1, NULL, NULL)
GO
INSERT [dbo].[Pricing] ([ProductID], [PricingID], [COSBeginQty], [COSCOLCode], [COSTrade], [COSTypeOfPrice], [COSIsActive], [COSPrice], [COSPriceTAG], [RowIndex], [COSCreateDate], [COSLastModifiedDate]) VALUES (N'94d67d13-e4e6-4360-9b7a-1cef7d997297', N'5ba0a6e9-53ed-4b9c-a9eb-2b09c41eb56c', 2, N'MAN', N'T2', N'A         ', 1, CAST(3456.234 AS Decimal(12, 3)), N'6ce7d421-e49a-469f-ae4c-a8bbb2f432fc', 3, NULL, NULL)
GO
INSERT [dbo].[Pricing] ([ProductID], [PricingID], [COSBeginQty], [COSCOLCode], [COSTrade], [COSTypeOfPrice], [COSIsActive], [COSPrice], [COSPriceTAG], [RowIndex], [COSCreateDate], [COSLastModifiedDate]) VALUES (N'e2216b52-66a9-4c29-a8ec-83c6ae03cd18', N'a8c27e9a-120c-47f2-bdd9-3e9e934ca237', 12, N'TEM', N'T1', N'B         ', 1, CAST(7234.000 AS Decimal(12, 3)), N'555c0f25-6af9-4114-8f11-096f0e5c7bcd', 1, NULL, NULL)
GO
ALTER TABLE [dbo].[Pricing] ADD  CONSTRAINT [DF_Pricing_ProductID]  DEFAULT (newid()) FOR [ProductID]
GO
ALTER TABLE [dbo].[Pricing] ADD  CONSTRAINT [DF_Pricing_PricingID]  DEFAULT (newid()) FOR [PricingID]
GO
ALTER TABLE [dbo].[Pricing] ADD  CONSTRAINT [DF_Pricing_COSPriceTAG]  DEFAULT (newid()) FOR [COSPriceTAG]
GO

问题的解决方案如下为BLUEFEET

select *, row_number() over(partition by ProductID order by ProductID) rn
from dbo.pricing;

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('Pricing') and
               C.name LIKE '%COS%'
               and C.name Not in ('COSCreateDate', 'COSLastModifiedDate')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name 
                         + cast(t.rn as varchar(10)))
                    from
                    (
                      select row_number() over(partition by productid 
                                               order by productid) rn
                      from Pricing
                    ) t
                     cross apply 
                      sys.columns as C
                   where C.object_id = object_id('Pricing') and
                         C.name LIKE '%COS%'
                     and C.name Not in ('COSCreateDate', 'COSLastModifiedDate')
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select *
      from
      (
        select ProductID,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select ProductID,
              PricingID, 
              cast(COSBeginQty as varchar(50)) COSBeginQty,
              cast(COSCOLCode as varchar(50)) COSCOLCode,
              cast(COSTrade as varchar(50)) COSTrade,
              cast(COSTypeOfPrice as varchar(50)) COSTypeOfPrice,
              cast(COSIsActive as varchar(50)) COSIsActive, 
              cast(COSPrice as varchar(50)) COSPrice,
              cast(COSPriceTAG as varchar(50)) COSPriceTAG,
              RowIndex,
              row_number() over(partition by productid 
                                               order by productid) rn
          from Pricing
        ) x
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ('+ @colspivot +')
      ) p'

exec(@query)

2 个答案:

答案 0 :(得分:2)

如果没有看到完整的表结构或示例数据,看起来您可以使用动态SQL执行类似的操作。这会使用UNPIVOTPIVOT来获得结果:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

第一个@colsUnpivot获取UNPIVOT所需的列列表然后重新转动。您需要UNPIVOT,因为您希望结果包含每个列的多个版本 - CosBeginQty1, CosBeginQty2, CosBeginQty3

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('Pricing') and
               C.name LIKE '%COS%'
         for xml path('')), 1, 1, '')

获取@colsPivot的代码正在获取最终列。通过将CosBeginQty1, CosBeginQty2, CosBeginQty3应用于表中的每一行来检索这些值(row_number)。

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name 
                         + cast(t.rn as varchar(10)))
                    from
                    (
                      select row_number() over(partition by productid 
                                               order by productid) rn
                      from Pricing
                    ) t
                     cross apply 
                      sys.columns as C
                   where C.object_id = object_id('Pricing') and
                         C.name LIKE '%COS%'
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

这个最后一部分生成要执行的动态sql语句。它使用@colsUnpivot@colsPivot值来形成要查询的最终sql语句。

set @query 
  = 'select *
      from
      (
        select ProductID, PricingID, RowIndex,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select ProductID,
              PricingID, 
              COSBeginQty,
              COSCOLCode,
              COSTrade,
              COSTypeOfPrice,
              COSIsActive, 
              COSPrice,
              COSPriceTAG,
              RowIndex,
              row_number() over(partition by productid 
                                               order by productid) rn
          from Pricing
        ) x
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ('+ @colspivot +')
      ) p'

exec(@query)

此解决方案将row_number()与每个值相关联,然后UNPIVOT将列与PIVOT相关联,并将row_number()添加到每个列名称。< / p>

PIVOTUNPIVOT可以静态执行,但由于您将PIVOT的值不明,因此您应该使用动态版本。如果您使用的是静态版本,那么它看起来像这样:

select *
from
(
   select ProductID, PricingID, RowIndex,
      col + cast(rn as varchar(10)) new_col,
      val
   from 
   (
     select ProductID,
         PricingID, 
         COSBeginQty,
         COSCOLCode,
         COSTrade,
         COSTypeOfPrice,
         COSIsActive, 
         COSPrice,
         COSPriceTAG,
         RowIndex,
         row_number() over(partition by productid 
                                               order by productid) rn
     from Pricing
   ) x
   unpivot
   (
      val
      for col in (COSBeginQty, COSCOLCode, COSTrade, COSTypeOfPrice
                 COSIsActive, COSPrice, COSPriceTAG)
   ) u
) x1
pivot
(
   max(val)
   for new_col in ([COSBeginQty1], [COSCOLCode1], [COSTrade1], [COSTypeOfPrice1],
                   [COSIsActive1], [COSPrice1], [COSPriceTAG1],
                  [COSBeginQty2], [COSCOLCode2], [COSTrade2], [COSTypeOfPrice2],
                   [COSIsActive2], [COSPrice2], [COSPriceTAG2])
) p

编辑#2,应用您的示例数据,脚本如下所示:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('Pricing') and
               C.name LIKE '%COS%'
               and C.name Not in ('COSCreateDate', 'COSLastModifiedDate')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name 
                         + cast(t.rn as varchar(10)))
                    from
                    (
                      select row_number() over(partition by productid 
                                               order by productid) rn
                      from Pricing
                    ) t
                     cross apply 
                      sys.columns as C
                   where C.object_id = object_id('Pricing') and
                         C.name LIKE '%COS%'
                     and C.name Not in ('COSCreateDate', 'COSLastModifiedDate')
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select *
      from
      (
        select ProductID, PricingID, RowIndex,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select ProductID,
              PricingID, 
              cast(COSBeginQty as varchar(50)) COSBeginQty,
              cast(COSCOLCode as varchar(50)) COSCOLCode,
              cast(COSTrade as varchar(50)) COSTrade,
              cast(COSTypeOfPrice as varchar(50)) COSTypeOfPrice,
              cast(COSIsActive as varchar(50)) COSIsActive, 
              cast(COSPrice as varchar(50)) COSPrice,
              cast(COSPriceTAG as varchar(50)) COSPriceTAG,
              RowIndex,
              row_number() over(partition by productid 
                                               order by productid) rn
          from Pricing
        ) x
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ('+ @colspivot +')
      ) p'

exec(@query)

请参阅SQL Fiddle with Demo

答案 1 :(得分:-1)

如果你可以使用动态sql,那么这可能适合你。

DECLARE @OUTPUT NVARCHAR(MAX)
SET @OUTPUT = "XXXXX"
SELECT @OUTPUT = @OUTPUT + "," + PricingID + COSBeginQty + COSCOLCode + COSTrade + COSTypeOfPrice + COSIsActive + COSPrice + COSPriceTAG + RowIndex
FROM Pricing
Where ProductID = XXXXX