2012-02-23 4 views
0

부드럽게, 나는 SQL 초보자입니다. 나는이 같은 이름의 테이블 autonumber_settings이 : 다음 수, 업데이트를 증가,SQL 서버에서 중복 된 자동 번호가 생성되었습니다.

Prefix | AutoNumber 
SO  | 112320 
CA  | 3542 

A A 새로운 판매 라인, 저장 프로 시저가 'SO'행에서 현재의 일련 번호 값을 읽이라고 생성 될 때마다 그 같은 행을 만들고 저장 프로 시저에서 다시 번호를 반환하십시오. 저장 프로 시저는 다음과 같습니다 :

ALTER PROCEDURE [dbo].[GetAutoNumber] 
(
    @type nvarchar(50) , 
    @out nvarchar(50) = '' OUTPUT 
) 
as 
set nocount on 

declare @currentvalue nvarchar(50) 
declare @prefix nvarchar(10) 

if exists (select * from autonumber_settings where lower(autonumber_type) = lower(@type)) 
begin 
    select @prefix = isnull(autonumber_prefix,''),@currentvalue=autonumber_currentvalue 
    from autonumber_settings 
    where lower(autonumber_type) = lower(@type) 

    set @currentvalue = @currentvalue + 1 

    update dbo.autonumber_settings set autonumber_currentvalue = @currentvalue where lower(autonumber_type) = lower(@type) 
    set @out = cast(@prefix as nvarchar(10)) + cast(@currentvalue as nvarchar(50)) 
    select @out as value 
end 
else 
    select '' as value 

이제 헤더와 라인을 모두 복사 명령을 중복 동일한 테이블을 액세스하는 또 다른 방법이있다. 경우에 따라 중복으로 인해 줄 번호가 중복됩니다. 두 절차는 때때로 복제에 의해 만들어진 선으로 처음부터 만든 같은 줄 번호를주고, 함께 잘 작동하지 않는 것 이유에

BEGIN TRAN 

IF exists 
(
     SELECT * 
     FROM autonumber_settings 
     WHERE autonumber_type = 'SalesOrderDetail' 
) 
BEGIN 
     SELECT 
       @prefix = ISNULL(autonumber_prefix,'') 
       ,@current_value=CAST (autonumber_currentvalue AS INTEGER) 
     FROM autonumber_settings 
     WHERE autonumber_type = 'SalesOrderDetail' 

     SET @new_auto_number = @current_value + @number_of_lines 

     UPDATE dbo.autonumber_settings 
     SET autonumber_currentvalue = @new_auto_number 
     WHERE autonumber_type = 'SalesOrderDetail' 
END 
COMMIT TRAN 

어떤 아이디어 : 여기에 해당 절차의 한 부분이다.

+3

IDENTITY 열을 사용하는 것이 좋습니다. 이것은 정확히 피할 수 있도록 설계된 것입니다. –

+0

'SELECT .../increase by one/UPDATE' 사이클 전체가 동시성에 안전하지 않습니다. 하나 이상의 프로세스가 동일한 시작 값을 가져 와서 하나씩 증가시킨 다음 새 값을 다시 쓸 수 있습니다. (b) SQL Server 2012가 'SEQUENCE'객체를 가져올 때까지 기다리거나 (c) 하나의 UPDATE가되도록 변경해야합니다 (즉, 동시성이 보장되도록 INT IDENTITY를 사용해야합니다. 다중 호출자가 여러 번 실행할 수없는 문. –

+1

또한 ** 왜 ** @ currentvalue'를'nvarchar (50)'변수로 정의합니까? 그게 수치가 아니니 ?? 그것이 숫자라면 - 숫자로 선언하십시오! –

답변

0

이것은 경쟁 조건 또는 자동 할당입니다. 두 번의 실행은 새 값이 데이터베이스에 다시 기록되기 전에 동일한 값을 읽을 가능성이 있습니다.

이 문제를 해결하는 가장 좋은 방법은 ID 열을 사용하고 SQL 서버가 자동 번호 할당을 처리하도록하는 것입니다.

sp_getapplock을 사용하여 autonumber_settings에 대한 액세스를 직렬화 할 수 없다면 예외입니다.

+0

자동 숫자 열의 숫자를 항상 숫자로 생각하면 본질적으로 해당 열을 가진 테이블을 현재 값으로 시드 (seeding)하여 다시 만들 수 있습니까? 즉, 저장 프로 시저의 코드를 변경해야합니까? – npeterson

+0

하나의 테이블에 여러 개의 ID 열을 사용할 수 없습니다. procs가 제시되므로 나는 그것이 당신을 위해 작동한다고 생각하지 않습니다. 자동 번호를 사용하는 테이블을보고 ID 열을 가질 수 있는지 확인해야합니다. – vickd

0

선택 항목에 반복 읽기를 사용할 수 있습니다. 그러면 행을 잠그고 값을 업데이트하고 커밋 할 때까지 다른 프로 시저의 선택을 차단합니다.

각 선택에 대해 from 절 뒤에 WITH (REPEATABLEREAD, ROWLOCK)을 삽입하십시오.

+0

이것은 흥미로운 아이디어입니다.이 부분을 조금 읽도록하겠습니다. – npeterson

관련 문제