更新一个包含单行但最初设置为NULL的表,并返回下一个可用的ID。

huangapple go评论68阅读模式
英文:

How update a table that contains to a single row but is initially set to NULL and return the next available id

问题

以下是您的代码的翻译部分:

我在一个存储过程中有以下代码,当行数设置为0时有效:

SET NOCOUNT ON;

BEGIN TRANSACTION

DECLARE @OutputDataID BIGINT

UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = [DataID] + 1

COMMIT

RETURN @OutputMetadataID

由于只包含一行,这个代码有效。`DataID`会增加1,其更新后的值会被返回并设置在`@OutputDataID`变量中,然后由我的存储过程返回。

当表中没有行时,如何处理初始值?难道唯一的方法是首先执行一个`SELECT`并进行检查吗?我真的希望能在单个`UPDATE`语句中实现这一点。

我尝试过使用COALESCE

UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = COALESCE([DataID],0) + 1

但没有成功。当执行存储过程时,我收到以下错误:

'GetNextDataId'存储过程尝试返回一个不允许的NULL状态,将返回0状态。

并且它也不会更新数据库。有什么想法吗?
英文:

I've got the following code in a stored procedure which works when the row is set to 0:

SET NOCOUNT ON;

BEGIN TRANSACTION

DECLARE @OutputDataID BIGINT

UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = [DataID] + 1

COMMIT

RETURN @OutputMetadataID

As it contains only a single row, this works. The DataID gets incremented by 1 and it's updated value gets returned and set in the @OutputDataID variable which is then returned by my stored procedure.

How can I handle this when for the initial value there are no rows in the table? Is the only way to perform a SELECT first and check? I was really hoping to achieve this in a single UPDATE statement.

I've tried COALESCE:

UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = COALESCE([DataID],0) + 1

But to no avail. I get the following error when I execute my stored procedure:

> 'GetNextDataId' procedure attempted to return a status of NULL, which is not allowed. A status of 0 will be returned instead.

And it does not update the database either.

Any ideas?

答案1

得分: 1

你可以使用 isnull 来检查返回是否为 null
return isnull( @OutputDataID ,@defaultIncrement)
你可以使用 @@ROWCOUNT 来检查数据表是否插入了数据
IF @@ROWCOUNT = 0
   INSERT INTO [MaxDataID] ([DataID]) VALUES (@defaultIncrement)
你可以使用 @defaultIncrement
alter proc Test
as

SET NOCOUNT ON;

BEGIN TRANSACTION
DECLARE @defaultValue BIGINT=1
DECLARE @defaultIncrement BIGINT=1


DECLARE @OutputDataID BIGINT
UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = COALESCE([DataID],0) + @defaultIncrement


IF @@ROWCOUNT = 0
   INSERT INTO [MaxDataID] ([DataID]) VALUES (@defaultValue)


COMMIT

return isnull( @OutputDataID ,@defaultValue)
英文:

you can to use isnull for check return null

return isnull( @OutputDataID ,@defaultIncrement)

and can use if @@ROWCOUNT for check data table for insert data

IF @@ROWCOUNT = 0
   INSERT INTO [MaxDataID] ([DataID]) VALUES (@defaultIncrement)

you can to use @defaultIncrement

alter proc Test
as

SET NOCOUNT ON;

BEGIN TRANSACTION
DECLARE @defaultValue BIGINT=1
DECLARE @defaultIncrement BIGINT=1


DECLARE @OutputDataID BIGINT
UPDATE [dbo].[MaxDataID]
SET @OutputDataID = [DataID] = COALESCE([DataID],0) + @defaultIncrement


IF @@ROWCOUNT = 0
   INSERT INTO [MaxDataID] ([DataID]) VALUES (@defaultValue)


COMMIT

return isnull( @OutputDataID ,@defaultValue)

答案2

得分: 1

以下是翻译的内容:

这里看起来是一个 XY 问题。正如在多次评论中提到的,SQL Server 可以通过使用 IDENTITYSEQUENCE 处理递增值的创建。IDENTITY 是列属性,而 SEQUENCE 是数据库对象,因此可以被 多个 表引用。

通常情况下,当使用 SEQUENCE 时,你会在一个 DEFAULT CONSTRAINT 中定义它的使用,然后类似于 IDENTITY,你可以在 INSERT 子句中省略该列,SQL Server 会自动处理值。

由于我们在这里没有你表的模式,我使用了一些简单的表来演示 IDENTITYSEQUENCE 的使用,尽管似乎你想要的是后者。

CREATE SEQUENCE dbo.MySequence
    START WITH 1 INCREMENT BY 1;
GO

CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
                          SequenceVal int NOT NULL CONSTRAINT DF_MyTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                          SomeDate date NULL,
                          TableName AS N'MyTable');

CREATE TABLE dbo.YourTable (ID int IDENTITY(1,1),
                            SequenceVal int NOT NULL CONSTRAINT DF_YourTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                            SomeDate date NULL,
                            TableName AS N'YourTable');

CREATE TABLE dbo.AnotherTable (ID int IDENTITY(1,1),
                               SequenceVal int NOT NULL CONSTRAINT DF_AnotherTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                               SomeDate date NULL,
                               TableName AS N'AnotherTable');
GO

INSERT INTO dbo.MyTable
DEFAULT VALUES;
INSERT INTO dbo.MyTable (SomeDate)
VALUES(GETDATE())

INSERT INTO dbo.YourTable
DEFAULT VALUES;

INSERT INTO dbo.MyTable
DEFAULT VALUES;

INSERT INTO dbo.AnotherTable (SomeDate)
VALUES(DATEADD(DAY, -1,GETDATE()))

INSERT INTO dbo.MyTable (SomeDate)
VALUES(DATEADD(DAY, -2,GETDATE()))
GO

SELECT *
FROM dbo.MyTable
UNION ALL
SELECT *
FROM dbo.YourTable
UNION ALL
SELECT *
FROM dbo.AnotherTable
ORDER BY SequenceVal ASC;

GO

DROP TABLE dbo.MyTable;
DROP TABLE dbo.YourTable;
DROP TABLE dbo.AnotherTable;
DROP SEQUENCE dbo.MySequence;

这将导致以下数据集:

ID SequenceVal SomeDate TableName
1 1 NULL MyTable
2 2 2023-04-13 MyTable
1 3 NULL YourTable
3 4 NULL MyTable
1 5 2023-04-12 AnotherTable
4 6 2023-04-11 MyTable

请注意,标识的值重复,但 SEQUENCE 是唯一的。

英文:

What you have here appears to be an XY Problem. As has been mentioned in the comments multiple times, SQL Server has facilities to handle the creation of incrementing values by the use of IDENTITY and SEQUENCE. An IDENTITY is a column property, whereas a SEQUENCE is a database object and so can be referenced by multiple tables.

Normally, when using a SEQUENCE you will define the use of it in a DEFAULT CONSTRAINT, then in a similar way to IDENTITY you can omit the column from the INSERT clause and SQL Server will handle the values automatically.

As we don't have a shema for your tables here, I use some simple table to demonstrate the use of both IDENTITY and SEQUENCE, though it seems it's the latter you want.

CREATE SEQUENCE dbo.MySequence
    START WITH 1 INCREMENT BY 1;
GO

CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
                          SequenceVal int NOT NULL CONSTRAINT DF_MyTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                          SomeDate date NULL,
                          TableName AS N'MyTable');

CREATE TABLE dbo.YourTable (ID int IDENTITY(1,1),
                            SequenceVal int NOT NULL CONSTRAINT DF_YourTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                            SomeDate date NULL,
                            TableName AS N'YourTable');

CREATE TABLE dbo.AnotherTable (ID int IDENTITY(1,1),
                               SequenceVal int NOT NULL CONSTRAINT DF_AnotherTableSequenceVal DEFAULT NEXT VALUE FOR dbo.MySequence,
                               SomeDate date NULL,
                               TableName AS N'AnotherTable');
GO

INSERT INTO dbo.MyTable
DEFAULT VALUES;
INSERT INTO dbo.MyTable (SomeDate)
VALUES(GETDATE())

INSERT INTO dbo.YourTable
DEFAULT VALUES;

INSERT INTO dbo.MyTable
DEFAULT VALUES;

INSERT INTO dbo.AnotherTable (SomeDate)
VALUES(DATEADD(DAY, -1,GETDATE()))

INSERT INTO dbo.MyTable (SomeDate)
VALUES(DATEADD(DAY, -2,GETDATE()))
GO

SELECT *
FROM dbo.MyTable
UNION ALL
SELECT *
FROM dbo.YourTable
UNION ALL
SELECT *
FROM dbo.AnotherTable
ORDER BY SequenceVal ASC;

GO

DROP TABLE dbo.MyTable;
DROP TABLE dbo.YourTable;
DROP TABLE dbo.AnotherTable;
DROP SEQUENCE dbo.MySequence;

This results in the following dataset:

ID SequenceVal SomeDate TableName
1 1 NULL MyTable
2 2 2023-04-13 MyTable
1 3 NULL YourTable
3 4 NULL MyTable
1 5 2023-04-12 AnotherTable
4 6 2023-04-11 MyTable

Notice that the value of the identity repeats, but the SEQUENCE is unique.

huangapple
  • 本文由 发表于 2023年4月13日 22:37:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76006735.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定