T-SQL::join sys.masked_columns 返回表中的所有列

Posted

技术标签:

【中文标题】T-SQL::join sys.masked_columns 返回表中的所有列【英文标题】:T-SQL :: joining sys.masked_columns returns all columns in table 【发布时间】:2022-01-02 20:53:18 【问题描述】:

我正在尝试通过sys.objects 加入INFORMATION_SCHEMA.COLUMNSsys.masked_columns

这是我的查询:

SELECT
    TABLE_SCHEMA,
    TABLE_NAME, 
    COLUMN_NAME,
    DATA_TYPE
        + CASE WHEN DATA_TYPE IN ('char', 'nchar', 'varchar', 'nvarchar', 'binary', 'varbinary')
                    AND CHARACTER_MAXIMUM_LENGTH > 0 
                  THEN COALESCE('(' + CONVERT(varchar, CHARACTER_MAXIMUM_LENGTH) + ')', '')
                  ELSE '' 
          END
        + CASE WHEN DATA_TYPE IN ('decimal', 'numeric') 
                   THEN COALESCE('(' + CONVERT(varchar, NUMERIC_PRECISION) + ',' + CONVERT(varchar, NUMERIC_SCALE) + ')', '')
                   ELSE '' 
          END AS Declaration_Type,
    --CASE WHEN IS_NULLABLE='NO' THEN 'NOT ' ELSE '' END + 'NULL' AS Nullable
    m.is_masked,
    m.masking_function 
FROM
    INFORMATION_SCHEMA.COLUMNS c
JOIN
    sys.objects o ON c.table_name = o.name
JOIN 
    sys.masked_columns m ON o.[object_id] = m.[object_id] 
ORDER BY 
    1, 2, 3

并返回:

TABLE_SCHEMA TABLE_NAME COLUMN_NAME Declaration_Type is_masked masking_function
Person EmailAddress BusinessEntityID int 1 email()
Person EmailAddress EmailAddress nvarchar(50) 1 email()
Person EmailAddress EmailAddressID int 1 email()
Person EmailAddress ModifiedDate datetime 1 email()
Person EmailAddress rowguid uniqueidentifier 1 email()

但是结果是错误的,因为它显示Person.EmailAddress中的所有列都被屏蔽了。

如果我检查这个查询:

SELECT c.name, tbl.name as table_name, c.is_masked, c.masking_function  
FROM sys.masked_columns AS c  
JOIN sys.tables AS tbl   
    ON c.[object_id] = tbl.[object_id]  
WHERE is_masked = 1;  

SSMS 仅返回 1 个屏蔽列:

name table_name is_masked masking_function
EmailAddress EmailAddress 1 email()

为什么要返回Person.EmailAddress 中的每一列?

【问题讨论】:

显然它也应该加入 column_id 而不仅仅是对象 id。否则,您如何期望仅过滤被屏蔽的列? (虽然使用 sys.columns 而不是 INFORMATION_SCHEMA.COLUMNS 因为这不会暴露 id INFORMATION_SCHEMA 与系统视图混在一起让我变成了一只悲伤的熊猫。根本不要使用INFORMATION_SCHEMA,除非您的意图是编写(稍微)可移植的代码,这不是因为屏蔽不是标准功能;这些“标准”视图实际上只是作为一个兼容层存在,并且(至少在 SQL Server 上)不是一个很好的实现。 也意味着你不会遇到像sys.objects o on c.table_name = o.name 这样的错误连接条件,如果同一个命名表存在于多个模式中,这将是不正确的 明白了,谢谢@JeroenMostert 和 MartinSmith 【参考方案1】:

感谢@MartinSmith 和@JeroenMostert 在评论中提供的帮助。

正确的解决方案是去掉 INFORMATION_SCHEMA.* 列并改用 sys. 列:

mc.name AS column_name, 
mc.is_masked, 
mc.masking_function
, [Type]         = 
    CASE 
      WHEN tp.[name] IN ('varchar', 'char') THEN tp.[name] + '(' + IIF(mc.max_length = -1, 'max', CAST(mc.max_length AS VARCHAR(25))) + ')' 
      WHEN tp.[name] IN ('nvarchar','nchar') THEN tp.[name] + '(' + IIF(mc.max_length = -1, 'max', CAST(mc.max_length / 2 AS VARCHAR(25)))+ ')'      
      WHEN tp.[name] IN ('decimal', 'numeric') THEN tp.[name] + '(' + CAST(mc.[precision] AS VARCHAR(25)) + ', ' + CAST(mc.[scale] AS VARCHAR(25)) + ')'
      WHEN tp.[name] IN ('datetime2') THEN tp.[name] + '(' + CAST(mc.[scale] AS VARCHAR(25)) + ')'
      ELSE tp.[name]
    END
FROM sys.masked_columns AS mc  
JOIN sys.tables AS tbl ON mc.[object_id] = tbl.[object_id]  
JOIN sys.types tp ON mc.user_type_id = tp.user_type_id
WHERE mc.is_masked = 1;  

【讨论】:

以上是关于T-SQL::join sys.masked_columns 返回表中的所有列的主要内容,如果未能解决你的问题,请参考以下文章