【问题标题】:SQL Server - Return SCHEMA for sysobjectsSQL Server - 为 sysobjects 返回 SCHEMA
【发布时间】:2009-05-27 18:59:02
【问题描述】:

在 sysobjects 上进行选择时如何获取 SCHEMA?

我正在修改一个名为 SearchObjectsForText 的存储过程,它只返回名称,但我还想包含 SCHEMA。

现在它正在做类似的事情:

SELECT DISTINCT name
FROM sysobjects

我想知道需要连接哪些表才能返回每个“名称”的 SCHEME。

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    如果您指的是 SQL Server 2005 或更高版本,请使用 sys.objects 而不是 sysobjects:

    SELECT  sys.objects.name, sys.schemas.name AS schema_name
    FROM    sys.objects 
    INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
    

    2005 年引入了模式。最多 2000 个,用户等于模式。 SQL Server 2000 的相同查询:

    SELECT  sysusers.name AS OwnerName, sysobjects.name
    FROM sysobjects
    INNER JOIN sysusers ON sysobjects.uid = sysusers.uid
    

    【讨论】:

    • 由于 SearchObjectsForText 存储过程的布局,我最终使用了这种方法。但我也喜欢“电线科学”,因为它更简单。
    • 值得指出的是,这将不会给出相同的结果。例如,sysobjects 将返回系统目录视图,而 sys.objects 则不会
    【解决方案2】:

    在 Sql Server 2005(及更高版本)上,您可以使用 sys.objects 视图:

    select 
      name                    as  ObjectName,     
      schema_Name(schema_id)  as  SchemaName
    from 
      sys.objects
    

    在 Sql Server 2000(及以下)中,“模式”具有不同的概念含义。来自 MSDN 的注释:

    在 SQL Server 的早期版本中,数据库可能包含称为“模式”的实体,但该实体实际上是数据库用户。 SQL Server 2005 是 SQL Server 的第一个版本,其中架构既是容器又是命名空间。

    【讨论】:

      【解决方案3】:

      你能改用Information_Schema view(s)吗?

      SELECT DISTINCT table_name, table_schema
      FROM INFORMATION_SCHEMA.TABLES
      

      根据the MSDN page(适用于 SQL Server 2008 及更高版本),

      不要使用 INFORMATION_SCHEMA 视图来确定对象的架构。查找对象架构的唯一可靠方法是查询 sys.objects 目录视图。

      但是,似乎他们可能指的是您有一个表名并试图找到它的架构的问题,如果有多个同名的表(在不同的架构中),这将不起作用。如果您要查询多个结果(而不仅仅是尝试查找特定表的架构),那么应该没问题。

      【讨论】:

      • 我希望可以,但我不想对现有的存储过程进行太多更改,而仅仅进行联接会更容易。无论如何感谢您的建议。我给了你一个赞成票。 :)
      • 不使用 INFORMATION_SCHEMA 视图来确定对象的架构?发誓!对我来说,这听起来像是一个必须修复的错误,而不是 MSDN 中记录的功能。如果您同意,请务必在 MSDN 网站上提交反馈。
      • @Alex 我绝对确定“确定对象的模式”意味着,给定一个表名(或对象 ID),找出它的模式是什么。是的,使用 INFORMATION_SCHEMA 视图执行此操作是不可靠的,因为 information_schema 视图不公开对象 id,因此只知道表名,在许多模式下可以有许多同名的表。如果您只是枚举对象列表及其模式和名称,则使用 INFORMATION_SCHEMA 视图是完全安全的。请注意,您也可以在对象 ID 上使用系统函数来返回架构名称。
      • @bdukes 鉴于我的上述评论,您是否反对更改您的答案?我很确定它们并不意味着 INFORMATION_SCHEMA 视图本身的架构信息不可靠。这确实是在文档中提出的一个奇怪的声明。
      【解决方案4】:

      我倾向于使用更集中的“sys”视图 - sys.procedures 而不是 sys.objects。您需要将其与 sys.schemas 视图结合以获取架构名称等。

      select
          p.name, 
          s.name 'Schema',
          p.type_desc, p.create_date, p.modify_date
      from
          sys.procedures p
      inner join
          sys.schemas s ON p.schema_id = s.schema_id
      

      我将开始不再使用“sysobjects”,因为 Microsoft 在联机丛书中明确指出“sysobjects”将在未来的版本中被删除:

      此 SQL Server 2000 系统表作为视图包含在内以实现向后兼容性。我们建议您改用当前的 SQL Server 系统视图。要查找等效的系统视图,请参阅将 SQL Server 2000 系统表映射到 SQL Server 2005 系统视图。此功能将在 Microsoft SQL Server 的未来版本中删除。避免在新的开发工作中使用此功能,并计划修改当前使用此功能的应用程序。

      马克

      【讨论】:

      • 感谢您的想法。这是一个相当大的程序,但必须进行审查。它正在使用所有旧的系统视图。
      【解决方案5】:

      只是重复这里已经建议的内容,这是我使用的,在我的数据库中获取表、存储过程、视图和函数的列表:

      SELECT schema_Name(schema_id)  as  SchemaName,
             [name],              --  Name of the Table, Stored Procedure or Function
             [type]               --  'V' for Views, 'U' for Table, 'P' for Stored Procedure, 'FN' for function
      FROM sys.objects 
      WHERE [type_desc] IN ( 'USER_TABLE', 'SQL_STORED_PROCEDURE', 'VIEW', 'SQL_SCALAR_FUNCTION')
      AND [name] NOT LIKE 'sp_%'
      AND [name] NOT LIKE 'fn_%'
      ORDER BY 3 DESC,        --  type first
              1 ASC,          --  then schema
              2 ASC           --  then function/table name
      

      ...这就是我们的好朋友 Northwind 将返回的东西...

      【讨论】:

        【解决方案6】:

        在 SQL 200 中:

        select DISTINCT
          name            as  ObjectName,     
          USER_NAME(uid)  as  SchemaName
        from 
          sysobjects
        

        在 SQL Server 的早期版本中,数据库可能包含称为“模式”的实体,但该实体实际上是数据库用户。

        【讨论】:

          【解决方案7】:

          包含一个选项,可以删除以特定前缀开头的所有对象,也可以从特定模式中删除。 顺便说一句,我添加了额外的查询来获取默认情况下未存储在 sysobjects 上的所有类型。

          我已将整个示例脚本上传到 GitHub: DropAll_Dnn_Objects.sql

          第 1 部分:临时存储过程:

          IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
              DROP PROCEDURE _temp_DropAllDnnObjects;
          GO
          
          CREATE PROCEDURE _temp_DropAllDnnObjects
              @object_prefix NVARCHAR(30),
              @schema_name sysname = NULL
          AS
          BEGIN
              DECLARE @sname sysname, @name sysname, @type NVARCHAR(30)
              DECLARE @object_type NVARCHAR(255), @sql NVARCHAR(2000), @count INT = 0
          
              DECLARE curs CURSOR FOR
                  SELECT sname, [name], xtype 
                  FROM (
                      SELECT SCHEMA_NAME(schema_id) as sname, [name], [type] as xtype
                          FROM sys.objects
                          WHERE [type] IN ('U', 'P', 'FN', 'IF', 'TF', 'V', 'TR')
                              AND name LIKE @object_prefix + '%'
                              AND (@schema_name IS NULL OR schema_id = SCHEMA_ID(@schema_name))
                      UNION ALL
                      SELECT SCHEMA_NAME(schema_id) as sname, [name], 'TYPE' as xtype
                          FROM sys.types
                          WHERE is_user_defined = 1
                              AND [name] LIKE @object_prefix + '%'
                              AND (@schema_name IS NULL OR schema_id = SCHEMA_ID(@schema_name))
                      ) a
                  ORDER BY CASE xtype
                                  WHEN 'P'    THEN 1
                                  WHEN 'FN'   THEN 2
                                  WHEN 'IF'   THEN 3
                                  WHEN 'TF'   THEN 4
                                  WHEN 'TR'   THEN 5
                                  WHEN 'V'    THEN 6
                                  WHEN 'U'    THEN 7
                                  WHEN 'TYPE' THEN 8
                                  ELSE 9
                              END, name
          
              OPEN curs;
              FETCH NEXT FROM curs INTO @sname, @name, @type;
          
              WHILE @@FETCH_STATUS = 0
              BEGIN
                  SET @count = @count + 1
                  -- Configuration point 2
                  SET @object_type = CASE @type
                                  WHEN 'P'    THEN 'PROCEDURE'
                                  WHEN 'FN'   THEN 'FUNCTION'
                                  WHEN 'IF'   THEN 'FUNCTION'
                                  WHEN 'TF'   THEN 'FUNCTION'
                                  WHEN 'TR'   THEN 'TRIGGER'
                                  WHEN 'V'    THEN 'VIEW'
                                  WHEN 'U'    THEN 'TABLE'
                                  WHEN 'TYPE' THEN 'TYPE'
                              END
                  SET @sql = REPLACE(REPLACE(REPLACE('DROP <TYPE> [<SCHEMA>].[<NAME>];', 
                                  '<TYPE>', @object_type),
                                  '<SCHEMA>', @sname),
                                  '<NAME>', @name)
          
                  BEGIN TRY  
                      PRINT @sql
                      EXEC(@sql)
                  END TRY  
                  BEGIN CATCH  
                      PRINT 'ERROR: ' + ERROR_MESSAGE()
                  END CATCH  
                  FETCH NEXT FROM curs INTO @sname, @name, @type;
              END;
          
              PRINT CONCAT('Objects Found: ', @Count)
              PRINT ''
              PRINT '------------------------------------------------------'
              PRINT ''
          
              CLOSE curs;
              DEALLOCATE curs;
          
              RETURN @Count
          END;
          GO
          

          它会继续出错(并显示错误消息)。它将返回找到的所有对象的计数。

          第 2 部分:使用参数调用存储过程:

          您可以创建一个 WHILE 循环来运行命令,直到没有留下任何对象(依赖项),如下所示:

          DECLARE @count INT = 1
          WHILE @count > 0 EXEC @count = _temp_DropAllDnnObjects 'dnn';
          SET @count = 1
          WHILE @count > 0 EXEC @count = _temp_DropAllDnnObjects 'aspnet';
          SET @count = 1
          WHILE @count > 0 EXEC @count = _temp_DropAllDnnObjects 'vw_aspnet';
          GO
          

          第 3 部分:最后,摆脱程序:

          IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
              DROP PROCEDURE _temp_DropAllDnnObjects;
          GO
          

          【讨论】:

            【解决方案8】:

            为什么不使用它来填充您可以使用的临时表,而不是视图?

            这是我在存储过程中使用的解决方案

            这是动态获取架构并将其添加到数据库中的不同表以便动态获取其他信息的最佳方式

            select @sql = 'insert #tables SELECT ''[''+SCHEMA_NAME(schema_id)+''.''+name+'']'' AS SchemaTable FROM sys.tables'

            exec (@sql)
            

            当然#tables是存储过程中的动态表

            【讨论】:

              猜你喜欢
              • 2013-02-12
              • 2021-09-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-08
              相关资源
              最近更新 更多