SQL将11行返回的值转换为89列

SQL将11行返回的值转换为89列,sql,sql-server,pivot,Sql,Sql Server,Pivot,我需要一些将数据行转换为列的帮助 我的每一行由8列组成,我希望所有这些列都包含在最终的列列表中 通常,我会编写一个类似下面的select语句,以返回与特定ProductID相关的关于11的所有定价行 我返回的每一行都有关于显示所有返回值的信息: ProductID, CosBeginQty1 COSBeginQty1 COSCOLCode1 COSTrade1 COSTypeOfPrice1 COSIsActive1 COSPrice1 COSPriceTAG1 CosBeginQty2

我需要一些将数据行转换为列的帮助

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

通常,我会编写一个类似下面的select语句,以返回与特定ProductID相关的关于11的所有定价行

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

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
问题的解决方案如下所示,这要感谢蓝脚怪


在看不到完整的表结构或示例数据的情况下,似乎可以使用动态SQL执行类似的操作。这将使用UNPIVOT和PIVOT来获得结果:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)
第一个@colsunprovot,它获取需要取消pivot以重新透视的列的列表。您需要取消PIVOT,因为您希望结果包含每个列的多个版本—CosBeginQty1、CosBeginQty2、CosBeginQty3

获取@colsPivot的代码就是获取最后的列。这些值CosBeginQty1、CosBeginQty2、CosBeginQty3是通过将行号应用于表中的每一行来检索的

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)
此解决方案将一个行号与每个值相关联,然后取消对列的拆分,最后使用添加到每个列名的行号旋转列

PIVOT和UNPIVOT可以静态执行,但由于要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
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)
编辑2,应用示例数据,脚本如下所示:

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
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,请参见

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

我不确定pivot在这种情况下如何工作,因为我没有在原始select语句的每一列中预期的值的预定义范围或值。我不明白您在这篇文章中所做的可能重复-选择ProductID、PricingID、RowIndex col+castrn作为varchar10 new_col, val@Kobojunkie我写的时候漏掉了一个逗号,请看我的编辑。如果您发布一些示例数据或创建一个{SQL FIDLE]。此时,我正在猜测列中的数据。我得到一个错误消息,列COSBeginQty的类型与UNPIVOT列表中指定的其他列的类型冲突。您知道如何解决此问题吗?您必须将所有值强制转换为相同的数据类型。您将在取消PIVOT之前的select中执行此强制转换。是否你可以在此聊天吗?
DECLARE @OUTPUT NVARCHAR(MAX)
SET @OUTPUT = "XXXXX"
SELECT @OUTPUT = @OUTPUT + "," + PricingID + COSBeginQty + COSCOLCode + COSTrade + COSTypeOfPrice + COSIsActive + COSPrice + COSPriceTAG + RowIndex
FROM Pricing
Where ProductID = XXXXX