UNPIVOT 返回数据类型

Posted

技术标签:

【中文标题】UNPIVOT 返回数据类型【英文标题】:UNPIVOT Return Data Types 【发布时间】:2016-08-30 21:25:43 【问题描述】:

我正在使用UNPIVOT 运算符,并且返回了不需要的数据类型。查询返回未透视数据的 nvarchar 数据类型。当加入一个具有 varchar 数据类型的表时,我得到一个隐式类型转换。下面是一个将产生这些结果的示例。

有没有办法控制UNPIVOT返回的输出数据类型?我想让UNPIVOT 返回 varchar 数据类型。

CREATE TABLE #Data
(
    Facility varchar(10) NOT NULL,
    Dt datetime NOT NULL,
    VolumeType1 int NOT NULL,
    VolumeType2 int NOT NULL,
    VolumeType3 int NOT NULL
);

CREATE TABLE #Map
(
    Facility varchar(10) NOT NULL,
    Department varchar(15) NOT NULL,
    VolumeType varchar(15) NOT NULL
)

INSERT INTO #Data VALUES
('Building1', '08/01/2016', 2500, 2500, 30),
('Building1', '08/02/2016', 3000, 3000, 35),
('Building2', '08/01/2016', 2500, 2500, 30),
('Building2', '08/02/2016', 3000, 3000, 35)

INSERT INTO #Map VALUES
('Building1', 'Department1', 'VolumeType1'),
('Building1', 'Department2', 'VolumeType2'),
('Building2', 'Department3', 'VolumeType1')

SELECT
    *
FROM 
    #Data
    UNPIVOT
        (
            Volume FOR VolumeType IN (VolumeType1, VolumeType2, VolumeType3) 
        ) AS UNP
    JOIN #Map
        ON UNP.Facility = #Map.Facility
            AND UNP.VolumeType = #Map.VolumeType

【问题讨论】:

我已在 2008 年执行此操作,但没有看到任何错误 不会出错。如果您查看查询计划,您将看到隐式类型转换。这就是我要避免的。 你最好用你所看到的来更新你的问题! 【参考方案1】:

UNPIVOT 函数有点奇怪,它会从不同的列(具有相同的数据类型和长度)中获取数据并将其转换为行。

虽然它会转换数据,但它似乎在此过程中做出了一些假设。例如,您的 Volume 列获取 int 数据类型,因为这是您取消透视的每个列的数据类型,但问题在于您的 VolumeType 列 - 引擎不知道您是否有 varcharnvarchar 用于数据,因此当您执行 unpivot 时,它会给出 nvarchar(256)

如果您不想要隐式类型转换,那么我建议使用CROSS APPLY 来取消透视您的数据。这是几行代码,但如果需要,您可以包含显式数据类型。这是一个例子:

select *
from
(
    select Facility, Dt, VolumeType, Volume
    from #Data
    cross apply
    (
        select 'VolumeType1', VolumeType1 union all
        select 'VolumeType2', VolumeType2 union all
        select 'VolumeType3', VolumeType3
    ) c (VolumeType, Volume)
) UNP
JOIN #Map
        ON UNP.Facility = #Map.Facility
            AND UNP.VolumeType = #Map.VolumeType;

See Demo。这应该删除隐式转换,但如果没有,那么您可以在 CROSS APPLY 内执行转换:

select *
from
(
    select Facility, Dt, VolumeType, Volume
    from #Data
    cross apply
    (
        select cast('VolumeType1' as varchar(15)), VolumeType1 union all
        select cast('VolumeType2' as varchar(15)), VolumeType2 union all
        select cast('VolumeType3' as varchar(15)), VolumeType3
    ) c (VolumeType, Volume)
) UNP
JOIN #Map
        ON UNP.Facility = #Map.Facility
            AND UNP.VolumeType = #Map.VolumeType;     

See Demo.

您的问题与我在DBA.SE 上发布的关于为什么 UNPIVOT 要求所有数据类型长度相同的问题非常相似。

【讨论】:

以上是关于UNPIVOT 返回数据类型的主要内容,如果未能解决你的问题,请参考以下文章

错误:列“DOB”的类型与UNPIVOT列表中指定的其他列的类型冲突

当 unpivot 未检测到具有不同类型的字段时,雪花如何转换选择查询的所有字段?

SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例

oracle列转行函数

Excel 2010 Unpivot 数据或利用 MySQL 进行 Unpivot

UNPIVOT 多行分隔字符串的结果