根据在(https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine?view=sql-server-2017(中找到的SQL类型转换图表,我使用的所有数据类型都可以隐式转换为nvarchar类型。 这对我的目的来说是理想的,因此我希望这会起作用,认为 #CSV_Column_Titles 将确定所有列的类型:
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.
我知道为什么会发生这种情况;对于我试图做的事情,转换优先级规则(见 https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-type-precedence-transact-sql?view=sql-server-2017(是"向后"的。我预计隐式转换将从最具体/限制性的形式"向下抛弃"到最一般的形式 - 这将满足我的需求。
上面的代码片段来自创建"CSV 样式"表的过程。 隐式转换(到 nvarchar(将是理想的,因为 #QueryResults 作为参数传入,并且可以具有任意数量的任何类型的列。 (对于那些好奇的人,#CSV_Column_Titles 是通过使用动态 SQL 从 #QueryResults 中提取列标题来创建的。
我试图通过创建一个使用的已定义类型(nvarchar 的别名(来解决优先级问题,但被拒绝了"创建"权限(并且知道它永远不会被授予(。
在我进一步研究使用动态 SQL 之前,是否有一些简单的方法(理想情况下隐式(将每列"向下转换"到 nvarchar,而不必使用显式强制转换/转换?
顺便说一句,如果我必须动态sql,我看到它做类似的事情(这是概念性的,而不是实际的SQL代码(:
INSERT INTO #CSV_Output
SELECT * from #CSV_Column_Titles
UNION ALL
EXECUTE( @Command ) -- instead of SELECT * FROM #QueryResults
其中@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_Titles 的临时表中提取的。
更新20180404
(叹息(在激烈的战斗中,你往往看不到树木的森林...... 我犯了两个错误:假设联合中的第一个 Select * 将(隐式地(确定最终结果集的列类型,并试图一步完成很多事情。
接受答案的关键点是在进行联合之前进行转换。
就我而言,不需要联合,我所要做的就是将(转换后的(值插入 #CSV_Output 并将其传递回调用脚本。
如果您不介意额外的 I/O,则可以在没有动态 SQL 的情况下执行此操作。
首先,使用输出表的架构创建一个临时表(使用带有负谓词的 SELECT/INTO(。将查询 #2 插入到此临时表中,以便它将隐式转换为这些目标类型。在您的情况下,这都是NVARCHAR(MAX(。
--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 )