0

我创建了一个针对服务器上所有数据库运行的 SQL Server 2008 代理作业。我正在使用未记录的 MS 程序,sp_MSforEachDB. 我只指定要处理的某些数据库,当找到这些数据库时,如果ERROR_NUMBER = 208,我想创建一个表并处理以继续到下一个数据库。我还想省略系统数据库,这样表格就不会在系统数据库中创建。我虽然通过指定要处理的数据库的名称,但可以创建一个不存在的表。如果在特定数据库上设置了“焦点”,我在下面显示的代码有效。此外,当我运行它时,我在主数据库中创建了一个表,我不想这样做。我试图用我创建的代码做的是: 1. 选择 SQL 服务器上名称为“xyz_%”的所有数据库 2. 如果表“SESSIONS”存在,则删除所有早于 5 分钟的记录 3. 如果表“SESSIONS”不存在,然后创建它并继续处理 - 这就是我得到的地方208 error - invalid object because this table does not exist 当作业发现没有 Sessions 表时,作业停止并且不处理其他数据库。我需要处理 1 中的所有命名数据库。如果 SESSIONS 表不存在,我会收到一个 208 错误,提示“无效的对象名称'master.SchemaName.sessions'。如果我将'焦点'设置为没有会话表的数据库,我的代码将运行并创建表但我仍然收到错误 208 - Invalid object name 'master.SchemaName.sessions'。没有显示其他错误。

如果有人可以查看我的代码以了解我的问题出在哪里,那就太好了。

我已通过使用下面的 Try Catch 验证我收到了 208 错误。我在第二次尝试 Catch 时也收到错误 2760,表示指定的架构不存在或我无权访问。我是这台服务器的管理员。

我已经使用 SQL 几年了,我不认为自己是专家。我已经在 Google 上对此进行了研究,以得出下面的代码。任何帮助,将不胜感激。

declare @ERROR INT

BEGIN TRY

exec sp_MSforeachdb 'IF "[?]" NOT IN ("master", "model","msdb", "tempdb")
BEGIN
 DELETE FROM [?].schema.sessions WHERE name like ''xyz_%''
 AND sessionStart <DATEADD(mi, -5,GETDATE())
END'                  

END TRY

BEGIN CATCH
SELECT  ERROR_NUMBER() AS error_number,  ERROR_MESSAGE() AS error_message
    SELECT @ERROR = ERROR_NUMBER()
    If @ERROR = 208
    BEGIN TRY
     /* create the Sessions table */
     BEGIN
     CREATE TABLE  [SCHEMA].[SESSIONS](
       [authuser] [varchar](30) NULL,
       [sessionID] [char](36) NULL,
       [sessionStart] [datetime] NULL)

grant select,delete on reviewadmin.sessions to public;
     END
    END TRY  
 BEGIN CATCH 
  SELECT  ERROR_NUMBER() AS error_number,  ERROR_MESSAGE() AS error_message
 END CATCH 
 END CATCH
4

1 回答 1

1

您可以尝试使用DB_ID(),我相信DB_ID()始终是 1-4 (除非您有分发数据库)。理论上,只要检查 DB_ID() 是否大于 4:

exec sp_MSforeachdb 'IF DB_ID(''?'')) > 4
BEGIN
 DELETE FROM [?].schema.sessions WHERE name like ''xyz_%''
 AND sessionStart <DATEADD(mi, -5,GETDATE())
END' 

此外,您在错误处理程序中似乎没有使用正确的数据库 - 当然您创建表的 try catch 也应该在调用中sp_MSforeachdb

我的意思是在你的文本中你正在为每个数据库运行,包括在 try catch 中:

CREATE TABLE [?].[SCHEMA].[SESSIONS]
(
   [authuser]     [VARCHAR](30) NULL,
   [sessionID]    [CHAR](36) NULL,
   [sessionStart] [DATETIME] NULL
)

还有一件事——目前你似乎已经reviewadmin.sessions在你的权限授予代码中硬编码了值——我假设你的意思是成为你的新[?].[Schema].[Sessions]表——再次应该在调用中,sp_MSforeachdb这样它就知道要在哪个数据库上运行。

我希望我已经给了你足够的继续,我不在一台我可以编写和测试整个事情的机器上,我害怕!


如果您只想要名称为的数据库xyz_%

exec sp_MSforeachdb 'IF DB_NAME() LIKE ''xyz_%''
BEGIN
 DELETE FROM [?].schema.sessions WHERE name like ''xyz_%''
 AND sessionStart <DATEADD(mi, -5,GETDATE())
END'

请注意,我们现在可以跳过对 DB_ID > 4 的检查,因为无论如何都没有系统数据库符合您的命名约定。


好的,我重新考虑了这一点。与其尝试然后在失败时捕获错误,不如这个新计划如何:

  1. 检查数据库是否符合您想要的命名约定。
  2. 检查表是否存在。
  3. 如果没有创建表,请像以前一样授予权限。
  4. 做插入。

这应该有望做到:

EXEC Sp_msforeachdb 'IF ''?'' LIKE ''xyz_%''
                    BEGIN
                        IF OBJECT_ID(''?.REVIEWADMIN.Sessions'', ''U'') IS NULL
                        BEGIN
                            CREATE TABLE [?].ReviewAdmin.Sessions
                            (
                                [authuser]     [VARCHAR](30) NULL,
                                [sessionID]    [CHAR](36) NULL,
                                [sessionStart] [DATETIME] NULL
                            )

                            grant select,delete on reviewadmin.sessions to public;

                        END

                        DELETE FROM [?].ReviewAdmin.Sessions
                        WHERE sessionStart < DATEADD(mi, -5,GETDATE())

                    END'
于 2013-01-14T16:01:43.830 回答