Литой тип данных с переменной

Возможно ли в T-SQL использовать тип данных с типом переменной?

т.е. Хотя это не сработает, поскольку он ожидает строковый литерал, но получает суть:

select @DataType = Data_Type
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'emp'
and COLUMN_NAME = 'emp_id'

SELECT
cast(emp_id as @DataType)
FROM emp

Ответ 1

Нет, вам нужно будет использовать динамический SQL для этого, например.

DECLARE @sql NVARCHAR(MAX);

SELECT @sql = N'SELECT CAST(emp_id AS ' + Data_Type
 + ') FROM dbo.emp;'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'emp'
AND TABLE_SCHEMA = 'dbo' -- this might be important!
AND COLUMN_NAME = 'emp_id';

PRINT @sql;
-- EXEC sp_executesql @sql;

Однако это кажется мне неправильным. Почему вы не знаете типы данных своих столбцов?

Кроме того, вам понадобится гораздо более сложный запрос, так как вам нужно будет учитывать точность/масштаб/максимальную длину. Если emp_id является varchar, например, все результаты будут усечены до одного символа.

И, наконец, Я настоятельно рекомендую sys.columns над INFORMATION_SCHEMA.

Ответ 2

Мне нужно было сделать что-то подобное, поэтому я создал функцию, чтобы я мог возвращать литеральный тип данных, как это было бы необходимо для моего динамического SQL. Я был удивлен, что не смог найти такую ​​функцию, как это уже было создано: (Или, может быть, я не должен удивляться, поскольку CASTING через Dynamic SQL не по моей рекомендации... но на данный момент я не могу представить альтернативы, как исходная таблица является переменной)

В любом случае, это функция, которой кто-либо когда-либо понадобится. Обратите внимание, что до сих пор я включил только типы данных из таблицы, в которую я пытаюсь использовать CAST... поэтому я считаю, что каждый, кто использует это, должен будет следовать и включать в себя типы данных, которые им нужны, или, возможно, все остальные.

CREATE FUNCTION dbo.GetLiteralDataType( @TableName as VARCHAR(100), @ColumnName as VARCHAR(100) )
    RETURNS VARCHAR(100)
    AS
    BEGIN

        DECLARE @DataType as VARCHAR(100)
        DECLARE @FullDataType as VARCHAR(100)
        DECLARE @MaxLength AS INT
        DECLARE @Precision AS INT
        DECLARE @Scale AS INT


        SET @DataType =(SELECT TOP 1 y.name FROM SYS.TABLES t
        INNER JOIN SYS.COLUMNS c ON t.object_id = c.object_id
        INNER JOIN SYS.TYPES y ON y.system_type_id = c.system_type_id
        WHERE t.name = @TableName AND c.name = @ColumnName)

        SET @MaxLength =(SELECT TOP 1 c.max_length FROM SYS.TABLES t
        INNER JOIN SYS.COLUMNS c ON t.object_id = c.object_id
        INNER JOIN SYS.TYPES y ON y.system_type_id = c.system_type_id
        WHERE t.name = @TableName AND c.name = @ColumnName)

        SET @Precision =(SELECT TOP 1 c.precision FROM SYS.TABLES t
        INNER JOIN SYS.COLUMNS c ON t.object_id = c.object_id
        INNER JOIN SYS.TYPES y ON y.system_type_id = c.system_type_id
        WHERE t.name = @TableName AND c.name = @ColumnName)

        SET @Scale =(SELECT TOP 1 c.scale FROM SYS.TABLES t
        INNER JOIN SYS.COLUMNS c ON t.object_id = c.object_id
        INNER JOIN SYS.TYPES y ON y.system_type_id = c.system_type_id
        WHERE t.name = @TableName AND c.name = @ColumnName)

        IF @DataType ='decimal'
        BEGIN
            SET @FullDataType = 'DECIMAL('+ @Precision + ',' + @Scale + ')'
        END

        IF @DataType ='varchar'
        BEGIN
            SET @FullDataType = 'VARCHAR('+ @MaxLength + ')'
        END

        IF @DataType ='bit'
        BEGIN
            SET @FullDataType = 'BIT'
        END

        IF @DataType ='money'
        BEGIN
            SET @FullDataType = 'MONEY'
        END

        IF @DataType ='date'
        BEGIN
            SET @FullDataType = 'DATE'
        END

        RETURN @FullDataType 
    END