【问题标题】:Get New Primary Key Value Dynamically (Max Value + 1)动态获取新的主键值(最大值+1)
【发布时间】:2013-12-20 22:15:50
【问题描述】:

我正在尝试在 SQL Server 2008 中创建一个过程,以获取任何表的新主键值(最大值 + 1)(表名将是输入参数)...我的代码如下:

CREATE PROCEDURE [dbo].[SysGetNewPrimaryKey]
(@TableName AS NVARCHAR(100)) AS
BEGIN
SET NOCOUNT ON;

DECLARE @PrimaryKey AS NVARCHAR(128)
DECLARE @PrimaryKeyLength AS INT
DECLARE @MaxValue AS NVARCHAR(10)
DECLARE @sql AS NVARCHAR(4000)
DECLARE @ParmDefinition AS NVARCHAR(500)

DECLARE @_PKInfo TABLE
(
     DbName     NVARCHAR(128)
    ,OwnerName  NVARCHAR(128)
    ,TableName  NVARCHAR(128)
    ,ColumnName NVARCHAR(128)
    ,KeySeq     INT
    ,PkName     NVARCHAR(128)
)

INSERT INTO @_PKInfo EXEC sp_Pkeys @TableName

SET @PrimaryKey = (SELECT ColumnName FROM @_PKInfo)
SET @PrimaryKeyLength = (SELECT COLUMNPROPERTY( OBJECT_ID(@TableName),@PrimaryKey,'PRECISION'))

select @primaryKey, @PrimaryKeyLength

SET @sql = 'SET @MaxValueOUT = (SELECT (ISNULL(MAX(@PrimaryKeyIN), 1) + 1) FROM ' + quotename(@TableName) + ')'
SET @ParmDefinition = '@PrimaryKeyIN NVARCHAR(128),
                       @MaxValueOUT NVARCHAR(10) OUTPUT'

EXEC sp_executesql 
@sql, 
@ParmDefinition,
@PrimaryKeyIN = @PrimaryKey,
@MaxValueOUT = @MaxValue OUTPUT

SELECT RIGHT(REPLICATE('0', @PrimaryKeyLength) + @MaxValue, @PrimaryKeyLength)
END

GO

当我尝试执行此过程时,会出现以下错误: 消息 245,第 16 级,状态 1,第 2 行 将 nvarchar 值“CityCode”转换为数据类型 int 时转换失败。

请告知是什么问题。示例表可以是:

城市标签

城市代码 nvarchar(10) CityDesc nvarchar(250)

编辑部分:(在查看以下 cmets 后)

如果我将创建此列 IDENTITY 然后尝试运行以下脚本来了解我的问题

CREATE TABLE [dbo].[TblCity](
[CityCode] [int] IDENTITY(1,1) NOT NULL ,
[CityDesc] [nvarchar](250) NOT NULL DEFAULT (''),
[CreationUser] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_TblCity] PRIMARY KEY CLUSTERED
([CityCode] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,              ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY])
ON [PRIMARY]

GO

INSERT INTO TblCity (CityDesc, CreationUser) VALUES ('Jeddah', 'sa')
INSERT INTO TblCity (CityDesc, CreationUser) VALUES ('Riyadh', 'sa')
INSERT INTO TblCity (CityDesc, CreationUser) VALUES ('Dammam', 'sa')

SELECT * FROM TblCity

INSERT INTO TblCity (CityDesc, CreationUser) VALUES ('Taif', NULL) -- This statement raises ERROR
INSERT INTO TblCity (CityDesc, CreationUser) VALUES ('Taif', 'sa')

SELECT * FROM TblCity -- 4 is missing now

最好的问候

齐山

【问题讨论】:

  • 可能的目的是什么?即使您在这里解决了语法问题,在实际运行插入之前获取“下一个”IDENTITY 值又有什么意义呢?因为除非您先插入然后检索您生成的值,否则无法保证“下一个”值在您插入时仍然可用。
  • +1 对于亚伦的怀疑……我也有同样的担忧。如果你这样做是因为它不是一个 IDENTITY,你应该让它成为一个身份,并让 SQL Server 担心并发性和一致性。如果它已经是一个标识值,并且您想知道下一个生成的标识值是什么而不是试图手动潜入(坏主意),请使用DBCC CHECKIDENT(YourTable, NORESEED),它实际上处理了最最近的身份已被删除或回滚。
  • 我的表中已经有一个标识列,必须用于其他目的......我正在考虑删除另一列以使该列成为 IDENTITY 但会有一个问题好像由于任何错误记录都不会插入,即使 SQL Server 会增加值,并且键中会有间隙,这在审计时可能是一个问题。如果出现任何错误,有没有办法将 IDENTITY 重置为以前的值?
  • previous value是什么意思? Alice 插入 1,Carol 插入 2,Bob 尝试 3,Ted 插入 4,Bob 进行回滚。现在你有 1、2 和 4。你想接下来做 3,然后是 5?您真正需要的是新版本的审核员。当他们看到 SQL Server 2012 在干净重启时可以跳过多少值时,他们会感到很舒服。
  • @HABO .. 举个例子... Alice 插入 1,Carol 插入 2,Bob 尝试 3,但是 SQL 在插入语句中引发了一些错误。 Bob 更正了该错误并再次插入。但它插入“4”而不是 3。如果表中有 4,我不想再做 3,但如果插入语句中有任何错误,它应该重置为 MAX 值。尝试在我的问题中运行脚本以进一步解释我的问题

标签: sql-server-2008


【解决方案1】:

好的,伙计们,我决定使用 IDENTITY 列作为主键。至于在错误时重置 IDENTITY,我将在实施前与我的经理/同事进一步讨论。

感谢你们……再见

最好的问候

齐山

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 2022-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多