代码之家  ›  专栏  ›  技术社区  ›  Kepboy

而不是更新触发器和更新主键

  •  5
  • Kepboy  · 技术社区  · 16 年前

    在开发新软件时,我正在对现有数据库进行更改。还有相当多的遗留软件使用需要继续工作的数据库,例如,我希望维护现有的数据库表、进程等。

    现在我有桌子了

    CREATE TABLE dbo.t_station (
        tx_station_id        VARCHAR(4)    NOT NULL,
        tx_description       NVARCHAR(max) NOT NULL,
        tx_station_type      CHAR(1)       NOT NULL,
        tx_current_order_num VARCHAR(20)   NOT NULL,
    
        PRIMARY KEY (tx_station_id)
    )
    

    我需要在这个表中包含一个引用工厂(生产设施)的新字段,并将tx_current_order_num移到另一个表中,因为并非所有行都需要它。所以我创建了新表:

    CREATE TABLE Private.Plant (
        PlantCode   INT           NOT NULL,
        Description NVARCHAR(max) NOT NULL,
    
        PRIMARY KEY (PlantCode)
    )
    CREATE TABLE Private.Station (
        StationId   VARCHAR(4)    NOT NULL,
        Description NVARCHAR(max) NOT NULL,
        StationType CHAR(1)       NOT NULL,
        PlantCode   INT           NOT NULL,
    
        PRIMARY KEY (StationId),
    
        FOREIGN KEY (PlantCode) REFERENCES Private.Plant (PlantCode)
    )
    CREATE TABLE Private.StationOrder (
        StationId   VARCHAR(4)  NOT NULL,
        OrderNumber VARCHAR(20) NOT NULL,
    
        PRIMARY KEY (StationId)
    )
    

    现在,我不希望在两个地方有相同的数据,所以我决定将dbo.t_站表更改为视图,并提供代替触发器来执行删除、插入和更新。没问题,他们大部分都在工作。

    我的问题是更新触发器,更新主键列(tx_station_id)并更新到多行。

    在触发器块内,是否有任何方法连接插入和删除的[psuedo]表,以便我知道“更新前主键”和“更新后主键”?像这样的…

    UPDATE sta
        SET sta.StationId = ins.tx_station_id
        FROM Private.Station AS sta
            INNER JOIN deleted AS del
                INNER JOIN inserted AS ins
                    ON ROW_IDENTITY_OF(del) = ROW_IDENTITY_OF(ins)
                ON del.tx_station_id = sta.StationId
    

    在这个阶段,我在触发器块中放置了一个检查,如果主键列被更新,并且插入或删除的表中有多行,则触发器块将回滚更新。

    1 回复  |  直到 16 年前
        1
  •  3
  •   Peter Radocchia    16 年前

    简短的回答是不。

    能够 在private.station上放置一个代理键,并通过视图公开它,并使用它来标识值的前后。您不需要更改主键或外键关系,但必须通过视图公开一些不可更新的cruft,以便它出现在伪表中。如:

    alter table Private.Station add StationSk int identity(1,1) not null
    

    注意,如果使用select*,这可能会破坏旧应用程序。但是,没有显式插入列列表的插入语句应该是正常的。

    除此之外,还有 可以 在插入和删除之间进行一些未记录和一致的排序,这样行_number()over(order by nullif(stationid,stationid))将允许您加入这两个行,但我会非常犹豫是否走这条路。非常,非常犹豫。

    您是否有意不启用级联更新?它们在可以更新主键值时非常有用。如:

    CREATE TABLE Private.Station (
        StationId   VARCHAR(4)    NOT NULL,
        Description NVARCHAR(max) NOT NULL,
        StationType CHAR(1)       NOT NULL,
        PlantCode   INT           NOT NULL,
        PRIMARY KEY (StationId),
        FOREIGN KEY (PlantCode) REFERENCES Private.Plant (PlantCode) 
          ON UPDATE CASCADE 
          -- maybe this too:
          -- ON DELETE CASCADE
    )
    

    有人可能有更好的把戏。等等看!