我有一个计算列,它使用标量值函数来评估它的值。由于某些原因,我需要创建列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和其他元数据函数,但是在没有使用系统对象的情况下找不到获取列类型的方法。
答案 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
还没有人回答......似乎没有泛型方法......
所以想一想:
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
)并且一切都很好。