【问题标题】:Database scheme, autoincrement数据库模式,自动增量
【发布时间】:2017-04-07 11:39:47
【问题描述】:

这里的数据库问题。 是否可以对第二个或第三个 ID 进行自动增量? 我需要做一些基于版本的东西,所以想象一下:

ID  Phrase  PhraseID    PhraseVersion
1   ""      1           1
2   ""      1           2
3   ""      1           3
4   ""      2           1

添加到数据库时,PhraseID 可以是相同的数字。 如果 PhraseID 存在,我希望 PhraseVersion 自动增加数量。 如果 PhraseID 不存在,我希望 PhraseVersion 重新开始,从 1 开始计数。

这可能吗?

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    我会为PhraseVersion 使用计算列,这将计算具有相同PhraseIDId 的行数小于或等于当前行。

    为此,您需要创建一个 UDF 来计算 PhraseVersion:

    CREATE FUNCTION dbo.GetPhraseVersion (
        @PhraseId int,
        @id int
    )
    RETURNS INT
    AS
    BEGIN
        RETURN (
            SELECT COUNT(*) 
            FROM T 
            WHERE PhraseId = @PhraseId 
            AND Id <= @id
        )
    END
    GO
    

    然后,使用计算列创建表:

    CREATE TABLE T
    (
        id int identity(1,1),
        PhraseId int,
        PhraseVersion as dbo.GetPhraseVersion(PhraseId, id)
    )
    
    GO
    

    现在进行测试 - 插入 4 条记录:

    INSERT INTO T (PhraseId) VALUES(1),(1),(1),(2)
    

    选择:

    SELECT *
    FROM T
    

    结果:

    id  PhraseId    PhraseVersion
    1   1           1
    2   1           2
    3   1           3
    4   2           1
    

    You can see a live demo on rextester.

    【讨论】:

    • 这对高频插入可靠吗?是否可能有重复的 PhraseId - PhraseVersion 对?
    • 我不知道。首先,我不知道您认为高频是什么,其次,我从未使用大量数据对其进行过测试。作为您的第二个问题,这不应该发生。
    • @ZoharPeled 在计算列上应用过滤器需要很长时间。
    • @AGH 我猜您指的是在 where 子句中使用计算列。不幸的是,由于此列基于 UDF,因此无法将其标记为持久化,因此无法编制索引。我不知道您实施的具体细节,因此我无法提供进一步的帮助。如果您有问题,我们随时欢迎您发布适当的问题。
    • @ZoharPeled 这个平台不允许我们重复问题。我有同样的问题,并尝试了您的回答评论了我的担忧。然而,这不是你的错,因为提问者没有在他的问题中提出这样的要求。
    【解决方案2】:

    这可以通过表上的插入触发器来完成:

    CREATE TABLE Phrases (
        ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
        PhraseID INT NOT NULL DEFAULT(0), 
        PhraseVersion INT NOT NULL DEFAULT(0))
    GO
    
    -- ==========================================================================================
    -- Author:         Donna Landy
    -- Create Date:    21 Nov 2019
    -- Purpose:        To populate the PhraseVersion column (subordinate numeric key) on Insert
    -- Note:           Must cater for >1 row being inserted when this trigger is called
    -- Strategy:       Construct a temp table with the rows we need to consider, then update one row at a time
    -- ==========================================================================================
    
    CREATE TRIGGER Phrases_Insert ON Phrases AFTER INSERT
    AS
    BEGIN
    
        DECLARE @ID INT
        DECLARE @PhraseID INT
        DECLARE @PhraseVersion INT
    
        DECLARE @i INT
        DECLARE @iMax INT
    
        -- Create and populate temp table
        IF OBJECT_ID('tempdb..#phrases', 'U') IS NOT NULL DROP TABLE #phrases
        CREATE TABLE #phrases (i INT IDENTITY(1,1) PRIMARY KEY, ID INT, PhraseID INT)
        INSERT INTO #phrases (ID, PhraseID) SELECT ID, PhraseID FROM inserted
    
        -- Scan temp table
        SET @i=1
        SELECT @iMax=MAX(i) FROM #phrases
    
        WHILE @i <= @iMax BEGIN
    
            -- Fetch PhraseID & PhraseVersion for the row we are going to update
            SELECT @ID=ID, @PhraseID=PhraseID FROM #phrases WHERE i=@i
    
            -- Find the highest current Ref
            SELECT @PhraseVersion=ISNULL(MAX(PhraseVersion),0) FROM Phrases WHERE PhraseID=@PhraseID
    
            -- Update the row 
            UPDATE Phrases SET PhraseVersion=@PhraseVersion+1 WHERE ID=@ID 
    
            -- Increment loop counter
            SET @i+=1
    
        END
    
        -- Remove temp table
        IF OBJECT_ID('tempdb..#phrases', 'U') IS NOT NULL DROP TABLE #phrases
    
    END
    GO 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 2012-03-10
      • 2014-11-18
      • 2020-06-17
      • 1970-01-01
      相关资源
      最近更新 更多