TSQL 插入难题

发布于 2024-07-18 17:45:00 字数 1311 浏览 5 评论 0原文

我有一张桌子。 该表需要存储有关位置的数值,因此最初我只有两列,没有递增列,给出以下内容:

RefID | TypeID
    1 | 1
    1 | 3
    1 | 6
    2 | 3
    3 | 5
    3 | 6

其中第一列是位置的引用,第二列是实际值。

问题是我如何决定给第一列赋予哪个值。 我的想法是添加一个自动递增字段来生成这些值,这样我就可以得到以下数据:

ID | RefID | TypeID
1  | 1   | 1
2  | 1   | 3
3  | 1   | 6
4  | 4   | 3
5  | 5   | 5
6  | 5   | 6

因此,自动编号列(第 1 列)充当参考列的种子。

所以我有两个问题 - 将标识列值复制到引用列,并将引用值返回给应用程序,以便在该位置有多个值时可以使用它。

我想出了这个存储过程:

CREATE PROCEDURE [dbo].[AddCaseType]
(
    @TypeID INTEGER,
    @CaseID INTEGER = NULL OUT 
)
AS
BEGIN

    INSERT INTO
        dbo.CaseTypeList(RefID, TypeID)
    VALUES
         ( ISNULL(@CaseID,SCOPE_IDENTITY()), @TypeID)

    Set @CaseID =  SCOPE_IDENTITY()
END
GO

ISNULL 检查 CaseID 上是否为 NULL,如果为 null 则使用 SCOPE_IDENTITY() 值。 然而,SCOPE_IDENTITY 在插入之前进行评估,因此返回生成的最后一个标识,而不是新的标识。

我无法使用相关表中的唯一值,因为如果用户编辑值,我需要完整跟踪。

所以我知道我想做什么,但只是没有知识或经验去做。

因此,封装一下:如何为集合中的第一项生成唯一值并返回该值,以便我可以将该值重用于该集合的其余部分?

另外,您也可以回答是否还有另一个,更简单的方法。 请记住 - 我是 SQL 方面的新手,所以我需要了解为什么会发生某些事情,因为我将来可能需要更改它。

更新:喝完一杯咖啡后,我注意到代码中存在一个错误 - 更改为三列的结果,因此 [ID] 成为 INSERT 语句第一部分中的 RefID。 这也使一些代码无效,从而部分改变了我的问题的性质。 对于这可能造成的混乱,我们深表歉意。

I have a table. The table needs to store a number values about a location, so initially I had just the two columns without the incrementing column, giving the following:

RefID | TypeID
    1 | 1
    1 | 3
    1 | 6
    2 | 3
    3 | 5
    3 | 6

Where the first column is the reference for a location and the second is the actual values.

The problem was how do I decide which value to give the first column. The idea I have is to add an auto-incrementing field to generate these values so I would have the following data instead:

ID | RefID | TypeID
1  | 1   | 1
2  | 1   | 3
3  | 1   | 6
4  | 4   | 3
5  | 5   | 5
6  | 5   | 6

So the autonumber column (column 1) acts as a seed for the reference column.

So I have two problems - the copying of the identity column value to the reference column, and returning the reference value to the application so it can be used if there is more than one value for the location.

I came up with this stored procedure:

CREATE PROCEDURE [dbo].[AddCaseType]
(
    @TypeID INTEGER,
    @CaseID INTEGER = NULL OUT 
)
AS
BEGIN

    INSERT INTO
        dbo.CaseTypeList(RefID, TypeID)
    VALUES
         ( ISNULL(@CaseID,SCOPE_IDENTITY()), @TypeID)

    Set @CaseID =  SCOPE_IDENTITY()
END
GO

ISNULL checks for NULL on CaseID and if it is null to use the SCOPE_IDENTITY() value. Howevert SCOPE_IDENTITY is evaluated prior to the insert and thus returns the last identity generated and not the new one.

I can't use a unique value from a related table as I need full tracking if a user edits the values.

So I know what I want to do, but just don't have the knowledge or experience to do it.

So to encapsulate: How can I generate a unique value for the first item of a set and return that value so I can reuse it for the rest of that set?

Also you could answer if there is another, simpler way. Please remember - I am a newbie at SQL stuff, so I need to understand why something is happening because I might need to change it in the future.

Update: After grabbing a coffee I noticed an error in my code - a result of the change to three columns, so [ID] becomes RefID in the first part of the INSERT statement. This also invalidates some of the code and thus partly changes the nature of my problem. Sorry for the confusion this may cause.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

是伱的 2024-07-25 17:45:00

当插入到具有 identity 列的表时,您无需为 identity 列指定任何内容:

DECLARE @ERR INT

INSERT INTO CaseTypeList (TypeID, CaseID) --Column1 is auto-number, skip it
VALUES (@TypeID, @CaseID)

-- capture error var and last inserted identity value
SELECT @ERR = @@ERROR, @ID = SCOPE_IDENTITY()

-- IF @ERR <> 0 handle error, otherwise return

您不需要标识插入或类似的内容,除非您想要明确控制数量。 在这种情况下,您不会将其设置为identity

另外,我对你的专栏有所猜测。


编辑:好的,看来您实际上根本不需要身份列。 相反,如果未提供,您需要生成序列中的下一个数字。 在这种情况下,您可以将身份列保留在那里 - 它不会造成任何损害,但如果您想要一个唯一键,可能会有所帮助:

CREATE PROCEDURE [dbo].[AddCaseType]
(
    @RefID     INTEGER = NULL OUT,
    @TypeID    INTEGER
)
AS

BEGIN TRANSACTION

  IF @RefID IS NULL BEGIN
    SELECT @RefID = MAX(RefID)+1 FROM CaseTypeList
  END

  IF @@ERROR <> 0 BEGIN ROLLBACK; RAISERROR('Could not get ID', 16, 1) END


  INSERT INTO
    CaseTypeList(RefID, TypeID)
  VALUES
    (@RefID, @TypeID)

  IF @@ERROR <> 0 BEGIN ROLLBACK; RAISERROR('Could not insert', 16, 1) END

COMMIT TRANSACTION 

注意:如果不能,您可能应该在 RefID 和 TypeID 上有一个唯一键约束是重复的。

When inserting into a table with an identity column, you don't specify anything for the identity column:

DECLARE @ERR INT

INSERT INTO CaseTypeList (TypeID, CaseID) --Column1 is auto-number, skip it
VALUES (@TypeID, @CaseID)

-- capture error var and last inserted identity value
SELECT @ERR = @@ERROR, @ID = SCOPE_IDENTITY()

-- IF @ERR <> 0 handle error, otherwise return

You don't need identity insert or anything like that unless you want to explicitly control the number. In that case, you wouldn't set it to identity.

Also, I kind of guessed on your columns.


Edit: OK, so it looks like you don't actually need the identity column at all. Instead, you need to generate the next number in a sequence if one isn't provided. In this case, you can leave the identity column in there--it won't hurt anything, but might help later if you want a single unique key:

CREATE PROCEDURE [dbo].[AddCaseType]
(
    @RefID     INTEGER = NULL OUT,
    @TypeID    INTEGER
)
AS

BEGIN TRANSACTION

  IF @RefID IS NULL BEGIN
    SELECT @RefID = MAX(RefID)+1 FROM CaseTypeList
  END

  IF @@ERROR <> 0 BEGIN ROLLBACK; RAISERROR('Could not get ID', 16, 1) END


  INSERT INTO
    CaseTypeList(RefID, TypeID)
  VALUES
    (@RefID, @TypeID)

  IF @@ERROR <> 0 BEGIN ROLLBACK; RAISERROR('Could not insert', 16, 1) END

COMMIT TRANSACTION 

Note: you should probably have a Unique Key Constraint on RefID and TypeID if there cannot be duplicates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文