&引用;“向下”;执行UNION ALL时强制转换列(MS Sql Server 2012)

&引用;“向下”;执行UNION ALL时强制转换列(MS Sql Server 2012),sql,sql-server,tsql,sql-server-2012,Sql,Sql Server,Tsql,Sql Server 2012,根据()中的SQL类型转换图,我使用的所有数据类型都可以隐式转换为nvarchar类型。这对于我的目的来说非常理想,因此我认为这会起作用,认为#CSV_Column_标题将决定所有列的类型: INSERT INTO #CSV_Output SELECT * from #CSV_Column_Titles -- n" columns, all columns are nvarchar( MAX ) ) UNION ALL SELECT * FROM #Query

根据()中的SQL类型转换图,我使用的所有数据类型都可以隐式转换为nvarchar类型。这对于我的目的来说非常理想,因此我认为这会起作用,认为#CSV_Column_标题将决定所有列的类型:

INSERT INTO #CSV_Output          
SELECT * from #CSV_Column_Titles   --  n" columns, all columns are nvarchar( MAX ) )
UNION ALL
SELECT * FROM #QueryResults       --  "n" columns, all must be implicitly converted to nvarchar( MAX )
但是,这会返回如下消息:

Msg 8114, Level 16, State 5, Line 120
Error converting data type nvarchar to float.
我知道为什么会这样;因为我要做的是转换优先规则(请参阅)是“向后的”。我预计隐式转换将从最具体/限制性的形式“向下”转换为最一般的形式,这将满足我的需要

上面的代码片段来自创建“CSV样式”表的过程。隐式转换(到nvarchar)是理想的,因为#QueryResults是作为参数传入的,它可以有任意数量的任意类型的列。(对于那些好奇的人,#CSV#Column#Titles是通过使用动态SQL从#QueryResults中提取列标题来创建的。)

我试图通过创建一个已使用的定义类型(nvarchar的别名)来绕过优先级问题,但被拒绝了“创建”权限(并且知道它永远不会被授予)

在进一步研究使用动态SQL之前,是否有一些简单的方法(理想情况下是隐式地)将每个列“向下转换”到nvarchar,而不必使用显式转换/转换


顺便说一句,如果我必须使用动态sql,我会看到它执行类似的操作(这是概念性的,而不是实际的sql代码):

其中@Command正在生成,如下所示:

Set @Command  =  'SELECT (CAST(' +  @ColumnName + ' ) as nvarchar (MAX)) as '' +  @ColumnName  +'' '
然后为#QueryResults的剩余列中的每一列追加一行:

Set @Command =  @Command + ' , (CAST(' + @ColumnName + ' ) as nvarchar (MAX)) as '' + @ColumnName  + '' '

Set @Command =   @Command + ' FROM #QueryResults' )
其中@ColumnName是从用于创建#CSV_Column_标题的临时表中提取的


更新日期:20180404

(叹气)通常在战争的热浪中,你看不到森林而看不到树木。。。我犯了两个错误:假设联合中的第一个Select*将(隐式地)确定最终结果集的列类型,并试图在一个步骤中完成很多工作

公认答案中的关键点是在进行联合之前进行转换


在我的情况下,不需要使用union,我所要做的就是将(转换后的)值插入到#CSV_输出中,并将其传递回调用脚本。

如果您不介意额外的I/O,您可以在不使用动态SQL的情况下执行此操作

首先,使用输出表的模式创建一个临时表(使用带有否定谓词的SELECT/INTO)。在这个临时表中插入查询#2,以便它将隐式转换为这些目标类型。在您的情况下,这都是NVARCHAR(MAX)


非常感谢,特别是您的快速回复,我们将于明天试用。这看起来非常适合我必须做的事情——特别是因为我不喜欢使用动态SQL(KISS规则)。这也是创建一个纯T-SQL过程的最后一块拼图,该过程可以接受(几乎)每种类型的结果集/表,并生成一个在其他地方使用的相应的“带标题行的CSV文件”结果集。你能给我指出一些解释这个方法如何/为什么工作的东西吗?@user1459519这只是类型转换规则。对于联合,服务器必须使用优先级,因为它被要求联合两个不同的数据集。另一方面,对于INSERT,目标都是NVARCHAR(MAX)。因此,插入到这些目标中的计划涉及将原始类型转换为NVARCHAR(MAX),因为它是一个插入,而不是一个联合。啊哈!这很有道理。我的错误是一步做得太多。你的解决方案很有魅力,我编辑了我的问题以反映你的解决方案。
Set @Command =   @Command + ' FROM #QueryResults' )
--This will create a table like #CSV_Output, to store intermediate results
SELECT * INTO #QueryResultsCast FROM #CSV_Output WHERE 0 = 1

--cast all via INSERT
INSERT INTO #QueryResultsCast
SELECT * FROM #QueryResults

--Original desired output (retrieving from #QueryResultsCast)
INSERT INTO #CSV_Output          
SELECT * from #CSV_Column_Titles   --  n" columns, all columns are nvarchar( MAX ) )
UNION ALL
SELECT * FROM #QueryResultsCast       --  "n" columns, all must be implicitly converted to nvarchar( MAX )