Согласно диаграмме преобразования типов SQL, найденной в (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine?view=sql-server-2017)), все используемые мной типы данных могут быть неявно преобразованы в тип 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://docs.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
(Вздох) Часто в пылу битвы вы не видите леса за деревьями ... Я сделал две ошибки: предполагая, что первый выбор * в объединении (неявно) определит типы столбцов финала набор результатов и пытается сделать многое за один шаг.
Ключевым моментом в принятом ответе является преобразование перед выполнением объединения.
В моем случае объединение не требуется, все, что мне нужно было сделать, это вставить (преобразованные) значения в #CSV_Output и передать их обратно вызывающему сценарию.