【问题标题】:SQL Server 2000 - How should I go about writing this script?SQL Server 2000 - 我应该如何编写这个脚本?
【发布时间】:2011-01-31 20:46:59
【问题描述】:

我写了我的 SQL 并遇到了一个问题,请参阅 here

因此,我正在询问正确的方法来做我想做的事情,而不是我认为的使用 EXEC 的技巧。如果 EXEC 是正确的方法,那么我对 SQL 有疑问,但会使用它。

我正在编写一个 SQL 脚本来创建/更新数据库。我的结构是这样的:

  Declare SafetyCheck=0
  Declare DBVersion=0
  Declare NewInstall=0
  Declare DropTables=0

  IF SafetyCheck=1
  Begin
    IF DropTables = 1
      Drop all tables in the database

    IF Config table doesn't exist
    Begin
      Create the Config Table
      NewInstall = 1
    End
    IF Other Table doesn't exist
      Create the other table
    IF Other Table doesn't exist
      Create the other table

    DBVersion = CheckTheDBVersion
    IF DBVersion is old
    Begin
      Alter tables to make them +1 version higher
      Insert some stuff
    End

    DBVersion = CheckTheDBVersion
    IF DBVersion is old
    Begin
      Alter tables to make them +1 version higher
      Insert some stuff
    End

    IF NewInstall = 1
    Begin
      Insert default data
    End
  End

从逻辑上讲,上面应该可以工作,但这不是因为我喜欢上面提到的问题。因此,据我所知,我有 EXEC 或 GO 选项。 EXEC,如上所述,我认为是一个黑客。它将字符串作为 SQL 执行,但我没有以动态方式使用它,我有静态 sql 坐在其中 - 对我来说似乎是错误的。据我所知,GO 会打破一切,因为它会重置变量。

此时我可以选择重新编写 SQL,所以如果我能以正确的方式来做,我会的。我只是不知道我猜的正确方法。

编辑(似乎正在运行的示例脚本):

我不得不分解上面示例中的 SafetyCheck 检查,因为我无法将 GO 放在 IF 语句中。这让它变得更丑陋了。

-- -- --
-- Run this once to create the initial tables
-- -- --
CREATE TABLE Config (
    ID          [int] IDENTITY(1,1) NOT NULL,
    [Key]       [nvarchar](255) NOT NULL,
    Value       [nvarchar](255) NOT NULL
)
ALTER TABLE Config ADD PRIMARY KEY (ID) 
CREATE TABLE Roles (
    ID              [int] IDENTITY(1,1) NOT NULL,
    Name            [nvarchar](25) NOT NULL,
    Created         [DateTime] NOT NULL
)
ALTER TABLE Roles ADD PRIMARY KEY (ID)

-- -- --
-- Below, this is the script thats causing errors
-- -- --

IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '#v')
    DROP TABLE #v
CREATE TABLE #v (n char(30),v char(30))

INSERT INTO #v (n,v) VALUES ('RunSQL', '1')         -- Set to 1 or this does nothing
INSERT INTO #v (n,v) VALUES ('DropTables', '0')     -- Set to 1 to drop existing tables
                                                    -- dont do this for an upgrade
                                                    -- dont do this is there are custom tables

GO
IF (SELECT v FROM #v WHERE n='RunSQL') = 0
BEGIN
    SELECT 'Nothing has been done. Read First, Run Later' AS Error
END


IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    IF (SELECT v FROM #v WHERE n='DropTables') = 1
    BEGIN
        -- Remove all tables if they exist
        EXEC sp_MSforeachtable @command1 = 'DROP TABLE ?'
    END
END
GO

IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Config')
    BEGIN
        CREATE TABLE Config (
            ID          [int] IDENTITY(1,1) NOT NULL,
            [Key]       [nvarchar](255) NOT NULL,
            Value       [nvarchar](255) NOT NULL
        )
        ALTER TABLE Config ADD PRIMARY KEY (ID) 

        -- Assume this is a new database
        INSERT INTO Config ([Key], Value) VALUES ('DBVersion', '3')
    END

    IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Roles')
    BEGIN
        CREATE TABLE Roles (
            ID              [int] IDENTITY(1,1) NOT NULL,
            Name            [nvarchar](25) NOT NULL,
            Created         [DateTime] NOT NULL,
            ModifiedDate    [DateTime] NOT NULL
        )
        ALTER TABLE Roles ADD PRIMARY KEY (ID)
    END
END
GO

-- Lookup the current verision of the database
IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    INSERT INTO #v (n,v) SELECT 'CMSDBVersion', Value FROM Config WHERE [Key]='DBVersion'
END
GO

-- Update old tables to be like the new ones
IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    IF (SELECT COUNT(v) FROM #v WHERE n='CMSDBVersion') = 0
    BEGIN
        -- Add newer fields to exiting tables
        ALTER TABLE Roles ADD ModifiedDate DateTime;
        INSERT INTO Config ([Key], Value) Values ('DBVersion', '3')
    END
END
IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    INSERT INTO #v (n,v) SELECT 'CMSDBVersion', Value FROM Config WHERE [Key]='DBVersion'
END
GO

IF (SELECT v FROM #v WHERE n='RunSQL') = 1
BEGIN
    IF (SELECT v FROM #v WHERE n='CMSDBVersion') = '3'
    BEGIN
        -- Add/Update the standard rules
        IF NOT EXISTS (SELECT * FROM Roles WHERE Name='CMS User Admin')
            INSERT INTO Roles (Name, Created, ModifiedDate) VALUES ('CMS User Admin', GETDATE(), GETDATE())
    END
END
GO

-- remove the temp table
DROP TABLE #v

【问题讨论】:

    标签: sql sql-server tsql sql-server-2000


    【解决方案1】:

    编写它的一种方法是将所有部分分解为单独的支持 SP。由于每个 SP 都是在执行时自行编译的,因此在单个批处理块(由 GO 分隔)内,不会对主 SP 的依赖对象和所有支持 SP 的一致性进行静态检查。

    除此之外,使用动态 SQL 重写查询以影响 DDL 更改,或使用 GO 语句将它们分成批次,正如您所发现的那样。

    编辑

    您显示的 sn-p 不起作用,因为:

    当 RunSQL = 0 时,这部分不运行

    -- Update old tables to be like the new ones
    IF (SELECT v FROM #v WHERE n='RunSQL') = 1
    

    这会导致 ModifiedDate 不添加到角色。当我把 RunSQL 改成 1 后,下一部分就不行了

    IF (SELECT v FROM #v WHERE n='CMSDBVersion') = ''
    

    因为之前的insert在表中没有放任何东西(Config中没有记录)

    INSERT INTO #v (n,v) SELECT 'CMSDBVersion', Value FROM Config WHERE [Key]='DBVersion'
    GO
    

    整个块应该只是

    -- Update old tables to be like the new ones
        IF NOT EXISTS (select * from syscolumns where name='ModifiedDate' and ID = OBJECT_ID('Roles'))
        BEGIN
            -- Add newer fields to exiting tables
            ALTER TABLE Roles ADD ModifiedDate DateTime;
            UPDATE Config SET Value = '3' WHERE [Key]='DBVersion'
        END
    

    【讨论】:

    • 但是如何在不重置所有变量的情况下使用 GO?
    • @Justin - 如果这是在 SP 中,您甚至不能有 GO 语句,因此请使用支持 SP。如果没有,并且这只是一个临时批处理,请将变量存储到临时表中并使用 (select whichvar_as_column from #tmpstorage) 引用它们
    • @cyberkiwi - 这只是我加载到管理工作室并运行的脚本。我已经将所有变量移到一个临时表中,并且我重新构造了 SQL 以将 GO 放在代码块的末尾,因为我将 GO 放在 Begin/End 中,但我仍然收到错误,因为 SQL如果 IF 失败,则不会跳过。
    • @justin - 不看脚本(或一些构建的示例),这将是水晶球凝视..
    • 我看到我在 SQL 中有其他错误,重新发布。看起来和你看到的问题一样。通过修复,一切似乎都可以与 sn-p 一起使用。现在修复大文件。感谢您的所有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多