【问题标题】:Cast datatype with variable使用变量强制转换数据类型
【发布时间】:2012-06-20 15:09:11
【问题描述】:

在 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

【问题讨论】:

  • 您可以将大多数类型转换为 sql_variant,尽管这通常是个坏主意
  • @AlexK。除了 geography、geometry、hierarchyid、image、text、ntext、timestamp、xml 和 LOB 类型,例如 varchar(max)、nvarchar(max) 和 varbinary(max)。

标签: sql-server tsql


【解决方案1】:

我需要做类似的事情,所以我创建了一个函数,以便我可以返回动态 SQL 所需的文字数据类型。我很惊讶我找不到这样的函数已经创建:(或者我不应该感到惊讶,因为我的建议不会通过动态 SQL 进行 CASTING ......但在这一点上,我想不出一个替代方案源表是可变的)

无论如何,这是任何人都需要它的功能。请注意,到目前为止,我只包含了我试图 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

【讨论】:

    【解决方案2】:

    不,您需要为此使用动态 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_idvarchar,则所有结果都将被截断为一个字符。

    最后,I strongly recommend sys.columns over INFORMATION_SCHEMA

    【讨论】:

    • 没有提到 sys 视图比 information_schema 视图更好...
    • 谢谢,我正在尝试寻找动态 sql 的替代方案。但怀疑是否存在。我受到数据库多年来设置方式的限制(抵抗更改)。数百个数据库具有相同的表,但某些列上的数据类型不同(smallint 与 int)等。使用 PowerShell 加载 sproc 我不希望每个数据库都有一个自定义的。我总是可以回到 .NET 实用程序,我必须强制数据类型,但正在研究流式处理,其中 .NET 不是调用应用程序。
    猜你喜欢
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 2016-11-25
    • 2021-01-24
    • 2015-08-17
    相关资源
    最近更新 更多