获得列类型的确定性方法

时间:2017-05-29 11:26:08

标签: sql-server tsql

我有一个计算列,它使用标量值函数来评估它的值。由于某些原因,我需要创建列Persisted并且要做到这一点,我需要使该函数具有确定性。我使用如下的查询来获取列类型:

SELECT 
    @dataType = DATA_TYPE
FROM 
    INFORMATION_SCHEMA.COLUMNS (NOLOCK)
WHERE 
    TABLE_SCHEMA = 'X' AND
    TABLE_NAME = @TableName AND 
    COLUMN_NAME = @ColumnName

当我尝试向函数添加WITH SCHEMABINDING子句(使其成为确定性)时,我收到以下错误:

  

无法架构绑定函数'X.MY_FUNCTION',因为它   引用系统对象'INFORMATION_SCHEMA.COLUMNS'。

如何以确定的方式获取列的类型?我研究了COLUMNPROPERTY和其他元数据函数,但是在没有使用系统对象的情况下找不到获取列类型的方法。

2 个答案:

答案 0 :(得分:1)

对于TSQL,TVF的SQL验证该函数是确定性的,但SQL无法验证您的函数是否具有确定性,如果它访问目录视图,因为它无法使用SCHEMABINDING。

您可以使用CLR TVF,SQL无法完全验证,但允许您将CLR TVF标记为确定性并在持久计算列中使用它。

答案 1 :(得分:0)

你可能会尝试这样的事情,但我不确定这是否会有所帮助......

SELECT o.name,c.name,t.name,c.max_length,c.precision,c.is_nullable
FROM sys.columns AS c
INNER JOIN sys.objects AS o ON c.object_id=o.object_id
INNER JOIN sys.types AS t ON c.system_type_id=t.system_type_id
WHERE o.name=@YourTableName
  AND c.name=@YourColumnName

更新最坏的情况:-D

还没有人回答......似乎没有泛型方法......

所以想一想:

DECLARE @cmd VARCHAR(MAX);
WITH AllColumns AS
(
    SELECT c.TABLE_NAME AS tbl
          ,c.COLUMN_NAME AS col
          ,c.DATA_TYPE AS tp
    FROM INFORMATION_SCHEMA.COLUMNS AS c
)
SELECT @cmd=REPLACE
     ('CASE @tablename '
     + (SELECT ' WHEN ''' + c1.tbl + ''' THEN \n'
        +(
            SELECT 'CASE @columnname \n'
                 + (
                        SELECT ' WHEN ''' + c2.col + ''' THEN ''' + c2.tp + '''\n'
                        FROM AllColumns AS c2
                        WHERE c2.tbl=c1.tbl
                        FOR XML PATH('')
                   )
                 + ' END'
         )
        FROM AllColumns AS c1
        GROUP BY c1.tbl
        FOR XML PATH(''))
     + ' END','\n',CHAR(13)+CHAR(10));

--DROP FUNCTION GetColumnType;
SET @cmd='CREATE FUNCTION GetColumnType(@tablename VARCHAR(250),@columnname VARCHAR(250)) ' + CHAR(13) + CHAR(10)
       + 'RETURNS TABLE AS RETURN ' + CHAR(13) + CHAR(10) 
       + 'SELECT @tablename AS TableName,@columnname AS ColumnName,' + @cmd + ' AS DataType;';

EXEC(@cmd);
GO

SELECT * FROM GetColumnType('SomeTable','SomeColumn'); 

这将创建一个内嵌TVF ,其中包含您需要的所有类型。每当您更改数据库的结构时,都会再次运行此脚本(首先使用DROP FUNCTION)并且一切都很好。