简体   繁体   English

SQL Server 2000-我应该如何编写此脚本?

[英]SQL Server 2000 - How should I go about writing this script?

I wrote out my SQL and ran into an issue, see here . 我写了我的SQL并遇到了问题,请参阅此处

So I'm asking the proper way to do what I want to do as apposed to, what I consider, a hack of using EXEC. 因此,我问一个适当的方法来完成我想做的事,这与我认为使用EXEC的技巧有关。 If EXEC is the proper way, then I have issues with SQL but will use it. 如果EXEC是正确的方法,那么我在使用SQL时会遇到问题,但会使用它。

I'm writing a SQL script to create/update a database. 我正在编写一个SQL脚本来创建/更新数据库。 I have it structured like so: 我有这样的结构:

  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

Logically the above should work, but it doesn't because of the issue I liked to above. 从逻辑上讲,上面的方法应该可以工作,但是由于我上面提到的问题,这不是可以的。 So i have the EXEC or the GO option as far as I can tell. 据我所知,我有EXEC或GO选项。 EXEC, as a said above, I think is a hack. 如前所述,EXEC我认为是hack。 Its executing a string as SQL, but I'm not using it in a dynamic manner, I have static sql sitting in it - just seems wrong to me. 它以SQL形式执行字符串,但是我没有以动态方式使用它,而是将静态sql放在其中-对我来说似乎是错误的。 As far as I can tell GO will break it all to, as it resets the variables. 据我所知,GO将重置所有变量。

I have the option to re-write the SQL at this point so if I can do it the correct way, I would. 此时,我可以选择重新编写SQL,因此,如果可以正确的方式进行操作,我会这样做。 I just don't know the correct way I guess. 我只是不知道我猜的正确方法。

EDIT (Example script that seems to be working): 编辑(似乎正在运行的示例脚本):

I had to break up the SafetyCheck check in the sample above because I can't put a GO inside a IF statement. 我不得不在上面的示例中分解SafetyCheck检查,因为我不能在GO语句中放入GO。 That made it a lot more ugly. 这使它变得更加难看。

-- -- --
-- 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

One way to write it is to break all the parts into separate support SPs. 一种编写方式是将所有部分分解为单独的支持SP。 Since each SP is compiled itself at the time it executes, there is no static check on the main SP for dependent objects and consistency across all support SPs, within a single batch-block (separated by GO). 由于每个SP都是在执行时自行编译的,因此在单个批处理块(由GO分隔)内,不会对主SP进行静态检查以检查相关对象以及所有支持SP的一致性。

Other than that, rewrite your query using dynamic SQL to effect DDL changes, or use GO statements to break them into batches, as you have discovered. 除此之外,您已经发现,使用动态SQL重写查询以实现DDL更改,或者使用GO语句将其分成批处理。

EDIT 编辑

The snippet you have shown doesn't work because: 您显示的代码段无效,因为:

When RunSQL = 0, this part doesn't run 当RunSQL = 0时,此部分不运行

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

Which causes ModifiedDate not to be added to Roles. 这将导致ModifiedDate不会添加到角色。 When I changed RunSQL to 1, the next part doesn't work 当我将RunSQL更改为1时,下一部分将不起作用

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

Because the prior insert put nothing in the table (there is no record in Config) 因为先前的插入未在表中放置任何内容(Config中没有记录)

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

That whole block should just be 那整个方块应该是

-- 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM