【问题标题】:How can i join sys.columns of view to sys.columns of the table it is referencing in T-SQL?如何将视图的 sys.columns 加入它在 T-SQL 中引用的表的 sys.columns?
【发布时间】:2015-06-11 08:00:04
【问题描述】:

我正在尝试将 sys.columns 中的记录加入一个视图,加入 sys.columns 中它所引用的表的记录,因为我需要这些值视图中选定列的 is_nullableis_computeddefault_object_id 列。

视图的 sys.columns 记录具有“不正确”的值,您可以通过运行以下示例查询来观察:

CREATE TABLE TestTable (
    FieldA int NOT NULL,
    FieldB int DEFAULT (1),
    FieldC as CONVERT(INT, FieldA + FieldB),
    FieldD int NOT NULL
)
GO

CREATE VIEW TestView WITH SCHEMABINDING AS
SELECT  FieldA, FieldC as TestC, FieldB + FieldC as TestD
FROM dbo.TestTable WHERE FieldD = 1
GO

SELECT  OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
        c.is_nullable as Nullable, c.is_computed as Computed,
   cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestTable')
GO

SELECT  OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
        c.is_nullable as Nullable, c.is_computed as Computed,
   cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestView')
GO

我曾尝试使用系统视图来连接依赖项,但它们没有提供关于视图中的哪一列引用表中的哪一列的信息:

-- dm_sql_referenced_entities gives us all columns referenced, but all records
-- have referencing_minor_id 0, so we do not know which column refers to what
SELECT * FROM sys.dm_sql_referenced_entities('dbo.TestView', 'OBJECT')
GO

-- sql_dependencies gives us all columns referenced, but all records has
-- column_id 0 so we can not use this either of joining the columns
SELECT * FROM sys.sql_dependencies WHERE object_id = OBJECT_ID('TestView')
GO

-- sql_expression_dependencies just tells us what table we are referencing 
-- if view is not created WITH SCHEMABINDING. If it is, it will return columns,
-- but with referencing_minor_id 0 for all records, so not able use this either
SELECT * FROM sys.sql_expression_dependencies
    WHERE referencing_id = OBJECT_ID('TestView')
GO

某人在 social.msdn 上提交的这个未答复的帖子似乎是同一个问题: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/4ae5869f-bf64-4eef-a952-9ac40c932cd4

【问题讨论】:

  • 我在研究时也发现了这个帖子,但是如果您在视图中选择了多个表或列的数量或顺序不匹配,则该解决方案不起作用:stackoverflow.com/a/10054481/1463929
  • 查询视图列的可空性和默认结果似乎是正确的。我能看到的唯一可能的分歧是是否计算了列。但是,从某种意义上说,视图的每一列都是“计算的”。
  • 我不是在争论 quires 的结果是否正确,但我需要知道 TestView TestC 指的是计算列,如果说 TestD 只指 FieldB,我会需要知道它引用的列有一个默认值。
  • 您可以理解,当您的第二段开始“视图的 sys.columns 记录具有“不正确”的值”时,我可能已经得到了这样的印象
  • 对,“不是想要的值”。我只关心表的值。实际用例是我想采用 is_nullable、is_computed 和 default_object_id,并确定在插入新记录时是否需要该列。在渲染客户端时,我们将包含一个“必需”位,以便能够在将实际插入命令发送到服务器之前检查客户端是否需要字段。

标签: sql-server tsql


【解决方案1】:

您说“我需要知道 TestView TestC 指的是计算列”。 SQL Server 2008 R2 不支持此功能(虽然不确定 2012,但我对此表示怀疑)。

首先您可以查询 sys.columns 或 INFORMATION_SCHEMA.COLUMNS,但您不会找到您想要的。

如果你深入挖掘,你很可能会尝试 sys.sql_expression_dependencies 和 sys.dm_sql_referenced_entities (N'dbo.TestView', N'OBJECT'),但是你可以在那里找到 table-column 映射,而不是 column-column。 SQL 服务器通过“高级”对象(表、触发器...)而不是其详细信息(列)存储依赖关系信息。您会在 sys.sysdepends 中找到相同的内容。事实上,依赖信息在 SQL Server 中是不可靠的。

最后,您唯一的可能就是自己解析视图主体。可以在 sys.sql_modules 中找到:

SELECT m.definition
FROM 
    sys.objects o
    JOIN sys.sql_modules m 
        ON m.object_id = o.object_id
WHERE 
    o.object_id = object_id('dbo.TestView')
    and o.type = 'V'

解析 T-SQL 非常非常困难,它真的会把你推到你努力的极限。例如,从视图中获取表引用应该或多或少容易,然后是表列,特别是如果您的视图是模式绑定的。但如果不是,那么……想想引用 OUTER APPLY 的星号,它引用递归 CTE……

无论如何,祝你好运!

【讨论】:

  • 如果您阅读了我的整个问题,您会发现我已经尝试过 sys.sql_dependencies、sys.sql_expression_dependencies 和 sys.dm_sql_referenced_entities。 “不支持”和“解析视图主体”不是可接受的解决方案。
  • 感谢您的反馈。是的,我通读了整个问题并理解了你所尝试的一切。我只是想让答案更详细。另外,我理解您为什么不能接受我的回答,但这就是它的方式 - 不支持。目前唯一的可能是解析查询:(
  • 我会看看我是否可以在 CLR 函数中使用 Microsoft.SqlServer.Management.SqlParser.dll 来解析从 sys.sql_modules 检索到的定义,并使用解析的列映射来获得我想要的。如果我让它工作,会再次在这里发布。
  • 哇!如果你得到它的工作,你可能是第一个。或者也许是少数几个之一。我承认,当我需要列依赖时,经过几天的浏览和挖掘,我放弃了。只需让用户选择数据类型的详细信息(提示:如果信息可用,请从依赖表中选择)。
  • 我使用 Microsoft.SqlServer.Management.SqlParser.Scanner 让它工作,但由于不同版本的 Sql Server 的部署问题,我们现在不得不回滚。我可能很快就会自己实现 T-SQL 标记器,并使用它而不是 Microsoft dll 中的 Scanner。
【解决方案2】:

目前,当创建视图时,有两个高级操作发生 - 解析和绑定。解析基本上是检查语句、关键字等的语法。绑定是将语句中的标识符(对象名、列名)映射到相应的对象(表、视图、函数、列等)和类型派生的过程。此外,如果视图类似于 SELECT 语句,您可以选择在 SELECT 列表中或在视图名称之后为列引用和表达式取别名(例如:create view v1(a) as select i from t)。

绑定后,我们只在元数据中保留列别名和派生类型,因为视图在逻辑上是从查询表达式派生的表。因此,目前无法确定列别名映射到的表达式或其包含的内容(列或函数或文字等) 获取您要查找的信息的唯一方法是解析视图定义并执行您自己的绑定。我相信我们已经有一个 bug 可以跟踪功能请求,以公开更丰富的依赖关系信息,这些信息涉及将别名映射到视图定义中的列表达式。

最后,SQL Server Developer Studio 或 Visual Studio 数据库项目使用托管 T-SQL 解析器来跟踪此类引用,以便您可以使用项目进行重构或重命名。 希望这有助于澄清问题/当前的实施。

【讨论】:

  • 感谢您的回复。您是否有此错误/功能请求的 URL?
【解决方案3】:

似乎误解是 object_id 是 sys.columns 中的主键的假设。它不是。 sys.columns 中的 object_id 与 sys.objects 中的 object_id 相关。 所以:

SELECT C.*
FROM sys.objects T
INNER JOIN sys.columns C
ON T.object_id = C.object_id
WHERE T.type in ('S','U') -- System Tables and User Tables
AND T.name = 'Address' -- Table Name
order by C.Column_ID

将返回 AdventureWorks 中“地址”表中的列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多