具有不同数据类型的SQL Server数据透视值

具有不同数据类型的SQL Server数据透视值,sql,sql-server,pivot-table,Sql,Sql Server,Pivot Table,我正在尝试在MSSQL 2016中以不同类型透视所有值。我找不到一种方法来透视不同的数据类型 第一个表是初始形式/结构。第二个表是所需的形状 我尝试使用以下SQL代码来透视我的值 选择 [id]作为[id], 名字, 姓, 生日, 地址:, 旗帜 数 从( 挑选 [cm].[key]作为[id], [cm].[column]作为[column], [cm].[string]作为[string], [cm].[bit]作为[bit], [cm].[xml]作为[xml], [cm].[numb

我正在尝试在MSSQL 2016中以不同类型透视所有值。我找不到一种方法来透视不同的数据类型

第一个表是初始形式/结构。第二个表是所需的形状

我尝试使用以下SQL代码来透视我的值

选择
[id]作为[id],
名字,
姓,
生日,
地址:,
旗帜
数
从(
挑选
[cm].[key]作为[id],
[cm].[column]作为[column],
[cm].[string]作为[string],
[cm].[bit]作为[bit],
[cm].[xml]作为[xml],
[cm].[number]作为[number],
[cm].[date]作为[date]
从[cmaster]到[cm]
)AS[t]
支点(
最大值([字符串])-!?!?
对于中的[列](
名字,
姓,
生日,
地址:,
旗帜
数
)
)AS[p]

我认为最好的选择是使用条件聚合,例如

SELECT  cm.id,
        FIRSTNAME = MAX(CASE WHEN cm.[property] = 'firstname' THEN cm.[string] END),
        LASTNAME = MAX(CASE WHEN cm.[property] = 'lastname' THEN cm.[string] END),
        BIRTHDATE = MAX(CASE WHEN cm.[property] = 'birthddate' THEN cm.[date] END),
        FLAG = CONVERT(BIT, MAX(CASE WHEN cm.[bit] = 'flag' THEN CONVERT(TINYINT, cm.[boolean]) END)),
        NUMBER = MAX(CASE WHEN cm.[property] = 'number' THEN cm.[integer] END)
FROM    cmaster AS cm
GROUP BY cm.id;
尽管如此,正如您所看到的,您的查询与您的EAV模型紧密耦合,这也是为什么EAV被视为SQL反模式的原因。您的备选方案是在子查询中创建一个列并以此为轴心,但您必须转换为单个数据类型,并失去一点类型安全性:

SELECT  id, FIRSTNAME, LASTNAME, BIRTHDATE, ADDRESS, FLAG, NUMBER
FROM    (
            SELECT  id = cm.[key],
                    [column] = cm.[column],
                    Value = CASE cm.type
                                WHEN 'NVARCHAR' THEN cm.string
                                WHEN 'DATETIME' THEN CONVERT(NVARCHAR(MAX), cm.date, 112)
                                WHEN 'XML' THEN CONVERT(NVARCHAR(MAX), cm.xml)
                                WHEN 'BIT' THEN CONVERT(NVARCHAR(MAX), cm.boolean)
                                WHEN 'INT' THEN CONVERT(NVARCHAR(MAX), cm.integer)
                            END
            FROM    cmaster AS cm
        ) AS t
        PIVOT
        (
            MAX(Value)
            FOR [column] IN (FIRSTNAME, LASTNAME, BIRTHDATE, ADDRESS, FLAG, NUMBER)
        ) AS p;

为了按照您的要求生成结果,首先我们需要将数据转换为与所有数据类型兼容的格式。VARCHAR非常适合这样做。然后使用简单的select查询准备基表,然后透视结果。 在最后一次投影中,如果需要,可以将数据转换回原始格式

此查询也可以动态编写,以便在添加记录时获得结果。这里我根据您的数据提供静态答案。如果你需要一个更通用的动态答案,请告诉我。所以我可以在这里发帖

--data insert scripts I used: 
 CREATE TABLE  First_Table
 (
 [id] int,
 [column] VARCHAR(10),
 [string] VARCHAR(20),
 [bit] BIT,
 [xml] [xml],
 [number] INT,
 [date] DATE

    )

 SELECT     GETDATE()


INSERT INTO  First_Table VALUES(1, 'FIRST NAME', 'JOHN' , NULL, NULL, NULL, NULL)
INSERT INTO  First_Table VALUES(1, 'LAST NAME', 'DOE' , NULL, NULL, NULL, NULL)
INSERT INTO  First_Table VALUES(1, 'BIRTH DATE', NULL , NULL, NULL, NULL, '1985-02-25')
INSERT INTO  First_Table VALUES(1, 'ADDRESS', NULL , NULL, 'SDFJDGJOKGDGKPDGKPDKGPDKGGKGKG', NULL, NULL)
INSERT INTO  First_Table VALUES(1, 'FLAG', NULL , 1, NULL, NULL, NULL)
INSERT INTO  First_Table VALUES(1, 'NUMBER', NULL , NULL, NULL, 20, NULL)



SELECT 
PIVOTED.* FROM

(
 --MAKING THE BASE TABLE FOR PIVOT
SELECT 
   [id]
   ,[column] AS [COLUMN]
   , CASE WHEN  [column]  = 'FIRST NAME' then [string] 
   WHEN [column]  = 'LAST NAME' then [string] 
   WHEN [column]  = 'BIRTH DATE' then CAST([date] AS VARCHAR(100))
   WHEN [column]  = 'ADDRESS' then CAst([xml] as VARCHAR(100)) 
   WHEN [column]  = 'FLAG' then CAST([bit] AS VARCHAR(100))
   else CAST([number] AS VARCHAR(100)) END AS  [VALUE]
FROM   First_Table
 ) AS [P]

 PIVOT
(

 MIN ([P].[VALUE])
 FOR [column]  in  ([FIRST NAME],[LAST NAME],[BIRTH DATE],[ADDRESS],[FLAG],[NUMBER])

  ) AS PIVOTED
结果:

只需用
CONVERT
/
CAST
将列名括起来即可。例如
CONVERT(datetime,BIRTHDATE)