2009-05-07 5 views
0

У меня есть стол. Таблица должна хранить множество значений о местоположении, поэтому изначально я только две колонки без увеличивающимся колонки, что дает следующее:TSQL Insert Conundrum

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 

Так колонка AutoNumber (колонок 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 проверки на NULL на CaseID и если оно равно нулю, чтобы использовать значение SCOPE_IDENTITY(). Однако SCOPE_IDENTITY оценивается до вставки и, таким образом, возвращает последнее генерируемое удостоверение, а не новое.

Я не могу использовать уникальное значение из связанной таблицы, так как мне нужно полное отслеживание, если пользователь редактирует значения.

Так что я знаю, что хочу, но просто не имею знаний или опыта для этого.

Итак, чтобы инкапсулировать: Как создать уникальное значение для первого элемента набора и вернуть это значение, чтобы я мог повторно использовать его для остальной части этого набора?

Также вы можете ответить, если есть другой, более простой способ. Пожалуйста, помните - я новичок в материалах SQL, поэтому мне нужно понять, почему что-то происходит, потому что мне может понадобиться изменить его в будущем.

Обновление: После взятия кофе я заметил ошибку в коде - результат изменения трех столбцов, поэтому [ID] становится RefID в первой части инструкции INSERT. Это также отменяет некоторые из кода и, таким образом, частично изменяет характер моей проблемы. Извините за путаницу, это может вызвать.

+0

@Graham: Можете ли вы добавить заголовки столбцов на таблицы образцов? –

+0

@ Майкл Харен. Готово. Также я заметил ошибку в моем коде, которая делает недействительной часть моей проблемы. –

+0

@Graham: Я обновил свой ответ, чтобы надеяться зафиксировать ваши изменения. Примечание по адресу @@ Identity или Scope_Identity(): он извлекает значение, которое * совсем недавно * было вставлено в желаемую область действия, а не значение * next *. Вот почему в моем ответе я сам генерирую номер внутри транзакции. –

ответ

5

При вставке в таблицу с 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.

Кроме того, я догадывался о ваших колоннах.


Edit: ОК, так что это выглядит как будто вы на самом деле не нужду столбец идентификаторов на всех. Вместо этого вам нужно сгенерировать следующее число в последовательности, если оно не предусмотрено.В этом случае, вы можете оставить столбец идентификации там - это ничего не повредит, но может помочь в дальнейшем, если вы хотите, один уникальный ключ:

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 

Примечание: вы должны, вероятно, иметь уникальный ключ Constraint на RefID и TypeID, если не может быть дубликатов.

+0

Что мой код пытался сделать, это использовать значение идентификатора для значения refID, если значение refID не указано. К сожалению, я изменил таблицу, но не обновил свой код соответствующим образом, и это также вызывало у меня ошибки. Главное остается верным: как я могу сгенерировать уникальное значение для первого элемента набора и вернуть это значение, чтобы я мог повторно использовать его для остальной части этого набора? –

+0

Если вы действительно хотите получить идентификационную информацию, замените последнюю проверку на ошибку следующим: «SELECT @ERR = @@ ERROR, @ID = SCOPE_IDENTITY()». Если вы хотите новый или существующий RefID, как вы сказали, не делайте ничего, поскольку он уже захвачен с помощью «SELECT @RefID ...» –

+0

Незначительная проблема с вашим кодом: что происходит, когда в CaseTypeList нет значений? SELECT возвращает NULL и вызывает ошибку, поскольку RefID не может быть нулевым. –