对不同类型的列使用动态取消透视

时间:2018-08-27 08:14:22

标签: sql sql-server tsql unpivot

我有一个包含约100列的表格,分别名为F1,F2,... F100。 我想按行查询数据,像这样:

F1: someVal1
F2: someVal2
...

我正在SP中进行所有操作,因此,我正在动态生成sql。 我已经成功生成了以下sql:

select CAST(valname as nvarchar(max)), CAST(valvalue as nvarchar(max)) from tbl_name unpivot
(
    valvalue for valname in ([form_id], [F1],[F2],[F3],[F4],[F5],[F6],[F7],[F8],[F9],[F10],[F11],[F12],[F13],[F14],[F15],[F16],[F17],[F18],[F19],[F20],[F21],[F22],[F23],[F24],[F25],[F26],[F27],[F28],[F29],[F30],[F31],[F32],[F33],[F34],[F35],[F36],[F37],[F38],[F39],[F40],[F41],[F42],[F43],[F44],[F45],[F46],[F47],[F48],[F49],[F50],[F51],[F52],[F53],[F54],[F55],[F56],[F57],[F58],[F59],[F60],[F61],[F62],[F63],[F64],[F65],[F66],[F67],[F68],[F69],[F70],[F71],[F72],[F73],[F74],[F75],[F76],[F77],[F78],[F79],[F80],[F81],[F82],[F83],[F84],[F85])
) u

但是在执行此查询时,出现此异常:

  

“ F3”列的类型与其他列的类型冲突   在UNPIVOT列表中指定。

我猜这是因为F3是varchar(100),而form_id,F1和F2是varchar(50)。根据我的理解,我不应该收到此错误,因为我将所有结果都转换为select语句中的nvarchar(max)。

此表具有各种列,例如datetime,smallint和int。 另外,此表中除一列外的所有列均具有SQL_Latin1_General_CP1_CI_AS冲突

此错误的解决方法是什么?

2 个答案:

答案 0 :(得分:1)

此解决方案是您必须使用子查询使所有列具有相同的类型并具有相同的长度。

尝试先CAST子查询中的值,然后再unpivot而不是select

select valname, valvalue 
from (
    SELECT  
        CAST([form_id] as nvarchar(max)) form_id, 
        CAST([F1] as nvarchar(max)) F1,
        CAST([F2] as nvarchar(max)) F2,
        CAST([F3] as nvarchar(max)) F3,
        CAST([F4] as nvarchar(max)) F4,
        ....
    FROM tbl_name 
) t1 unpivot
(
    valvalue for valname in ([form_id], [F1],[F2],[F3],[F4],[F5],[F6],[F7],[F8],[F9],[F10],[F11],[F12],[F13],[F14],[F15],[F16],[F17],[F18],[F19],[F20],[F21],[F22],[F23],[F24],[F25],[F26],[F27],[F28],[F29],[F30],[F31],[F32],[F33],[F34],[F35],[F36],[F37],[F38],[F39],[F40],[F41],[F42],[F43],[F44],[F45],[F46],[F47],[F48],[F49],[F50],[F51],[F52],[F53],[F54],[F55],[F56],[F57],[F58],[F59],[F60],[F61],[F62],[F63],[F64],[F65],[F66],[F67],[F68],[F69],[F70],[F71],[F72],[F73],[F74],[F75],[F76],[F77],[F78],[F79],[F80],[F81],[F82],[F83],[F84],[F85])
) u

以最简单的方式,我将CROSS APPLYVALUES一起使用来进行unpivot

SELECT * 
    FROM People CROSS APPLY (VALUES 
        (CAST([form_id] as nvarchar(max))),
        (CAST([F1] as nvarchar(max))),
        (CAST([F2] as nvarchar(max))),
        (CAST([F3] as nvarchar(max))),
        (CAST([F4] as nvarchar(max))),
        ....
    ) v (valvalue)

以下是一个有关CROSS APPLYVALUESunpivot的示例

我们可以看到People表中有许多不同的类型。

我们可以尝试使用castvarchar(max),让列为同一类型。

CREATE TABLE People
(
  IntVal int, 
  StringVal varchar(50), 
  DateVal date
)

INSERT INTO People VALUES (1, 'Jim', '2017-01-01');
INSERT INTO People VALUES (2, 'Jane', '2017-01-02');
INSERT INTO People VALUES (3, 'Bob', '2017-01-03');

查询1

SELECT * 
FROM People CROSS APPLY (VALUES 
    (CAST(IntVal AS VARCHAR(MAX))),
    (CAST(StringVal AS VARCHAR(MAX))),
    (CAST(DateVal AS VARCHAR(MAX)))
) v (valvalue)

the

| IntVal | StringVal |    DateVal |   valvalue |
|--------|-----------|------------|------------|
|      1 |       Jim | 2017-01-01 |          1 |
|      1 |       Jim | 2017-01-01 |        Jim |
|      1 |       Jim | 2017-01-01 | 2017-01-01 |
|      2 |      Jane | 2017-01-02 |          2 |
|      2 |      Jane | 2017-01-02 |       Jane |
|      2 |      Jane | 2017-01-02 | 2017-01-02 |
|      3 |       Bob | 2017-01-03 |          3 |
|      3 |       Bob | 2017-01-03 |        Bob |
|      3 |       Bob | 2017-01-03 | 2017-01-03 |

注意

使用unpivot时,需要确保unpivot列的日期类型相同。

答案 1 :(得分:0)

猫可以通过多种方式为您蒙皮,反之亦然。 开个玩笑,D-Shih的建议是您应该从什么开始,并可能使您回家和干dry。

在大多数情况下 本质上,UNPIVOT操作是将多行中的数据连接在一起。从CAST操作开始是最好的方法,因为它使数据类型相同(最好是字符串类型,如varchar或nvarchar),除了具有相同的类型外,对所有UNPIVOTED列使用相同的长度也是一个好主意

在其他情况下; 如果仍然不能解决问题,则需要更深入地研究并检查表上所有列的ANSI_Padding设置为ON还是OFF。在SQL Server的较新版本中,默认情况下大多数情况下此选项为ON,但是某些开发人员可以自定义某些列以将ANSI_PADDING设置为off。如果您有这样的混合设置,则最好将数据移动到ANSI_PADDING设置为ON的另一个表中。尝试在该表上使用相同的UNPIVOT查询,它应该可以工作。 检查ANSI_Padding状态

    SELECT name
    ,CASE is_ansi_padded 
    WHEN 1 THEN 'ANSI_Padding_On' 
    ELSE  'ANSI_Padding_Off'
    AS [ANSI_Padding_Check]
                      FROM sys.all_columns
    WHERE object_id = object_id('yourschema.yourtable')

在许多情况下,更适合交叉应用值。一切都取决于您,骑师选择赛马的机会。

干杯。