2009-05-20 5 views
4

私のようなものであるSQL文含むストアドプロシージャがあります。挿入時に列の値としてのアイデンティティを使用する方法

CREATE PROCEDURE SaveUser 
@UserName nvarchar(10), 
@FirstName nvarchar(150), 
@LastName nvarchar(150) 

AS 
BEGIN 

    INSERT INTO Users (UserName, FirstName, LastName) 
    VALUES (@UserName, @FirstName, @LastName) 

    SELECT SCOPE_IDENTITY() 

END 

は、一部のユーザーがシステムにログインすることができないと、ユーザー名を表示できません。しかし、UserNameフィールドにはユニークなインデックスがありますので、UserNameとして自動増分フィールドであるユーザーID#を挿入できるようにしたいと考えています。

MS SQL Serverのメソッドや変数を知っている人は、私のようなことをすることができますか?

INSERT INTO Users (UserName, FirstName, LastName) 
VALUES (ISNULL(@UserName, SCOPE_IDENTITY()),@FirstName,@LastName) 

編集私の意図は、今、私はちょうどこれは一致するであろうことを保証することができます方法で建てられているかどうかを知りたいと思い、次の

DECLARE @NextID int 
SET @NextID = IDENT_CURRENT(Users) + IDENT_INCR(Users) 


INSERT INTO Users (UserName, FirstName, LastName) 
VALUES (ISNULL(@UserName, @NextID), @FirstName, @LastName) 

ようなものを使用することです。

答えて

1

AFTER INSERTトリガーを追加して、挿入された表のIdentity列の値でUserNameフィールドを更新できます。

その後、
+0

このケースでは、複数のレコードの挿入を処理できるようにするために、一意のインデックスがあるためにトリガーの代わりに必要な場合があります。 – HLGEM

+0

これは動作しますが、トリガーは実際にはデータベースを複雑にします。私は可能な限りそれらを避けるだろう。 – Andomar

+0

は、ユーザー名に固有のインデックスがあるため機能しません。 – jellomonkey

3

INSERTのNULLまたはランダムな文字列、その後

INSERT INTO Users (UserName, FirstName, LastName) 
VALUES (ISNULL(@UserName, CAST(NEWID() AS varchar(50)),@FirstName,@LastName) 

UPDATE Users 
SET @UserName = CAST(SCOPE_IDENTITY() AS int) 
WHERE UserId = SCOPE_IDENTITY() 

SCOPE_IDENTITYを使用して更新(NEWIDが直接キャストしていない場合の謝罪は...今テストすることはできません)

それはすべてで行うことができます1つは集約されていますが、信頼できるものではありません(2回の呼び出し)。

+0

私は、数字の自動インクリメントID列であるユーザーID列を持っています。私は値がその列に挿入されるのを取得し、usernameが渡された場合にusername列にも使用したいと思います。 – jellomonkey

+0

申し訳ありませんが、私の間違いは1回目です。あなたはそれをすべて確実に一つにすることはできません – gbn

+1

+1 newid()は良いアイデアです。一意でなければならない場合は、2番目の更新が不要です – Andomar

0

2つのステップで実行する必要があります。この場合、単にNEWID()関数を使用して、ユーザー名に使用するランダムなGUID値を生成し、後でupdate文を使用して更新します。ストアドプロシージャを使用しているので、この場合に使用するステップの量は大きな問題を引き起こすことはありません。

NEWIDの詳細と、それは使用だが、代わりにID列を複製するhere

+0

NEWGUID for SQL Serverのリファレンスを教えてください? – gbn

+0

謝罪します。私はNEWID()を参照していました。それに応じて答えを更新しました – BinaryMisfit

2

を見つけることができ、また、検索時にこの問題を解決することができます。たとえば、任意のユーザーのユーザー名をNULLにするとします。

select 
    UserName = IsNull(UserName,UserId) 
from WebUsers 

EDIT:あなたは、その後のようなユーザー名を取得することができますが、名前にUNIQUE制約を好きなら、あなたは計算列を使用することができます

create table WebUsers (
    id int identity, 
    name varchar(12), 
    uniqueid as isnull(name,id) 
) 

create unique index ix_webusers_uniqueid on WebUsers (uniqueid) 

列一意IDは、計算カラムがあるが、それが翻訳しますあなたがそれを使うたびにisnull(name、id)に。この設定では、1つのクエリにユーザーを挿入できます。

ただし、重複するユーザーはありません。以下はエラーで救済されます:

insert into WebUsers (name) values ('The Ring') 

あなたはanynomousユーザーの名前が付いたユーザーのユーザー名、またはIDを見つけるために、一意IDで問い合わせることができます:

select uniqueid from WebUsers 
+0

私は私のアプリケーションに重大な影響を与える非ユニークであるためにユーザー名のインデックスを変更する必要があります。 – jellomonkey

+0

良い点は、Sql ServerはUNIQUEインデックスに複数のNULL行を許可しないことです。計算された列を持つ代替の答えを編集しました – Andomar

+0

計算された列の良い考え – gbn

0

どのトランザクションでラップについて、そしてあなたのspidをUserNameに使うだけです。このように:

CREATE PROC BlahBlah 
... 
BEGIN 
BEGIN TRAN UserInsert 
BEGIN TRY 

    INSERT INTO Users (UserName, FirstName, LastName)  
    VALUES (COALESCE(@UserName,@@SPID), @FirstName, @LastName) 

    IF @UserName IS NULL 
    BEGIN 
    DECLARE @MyUserID int 
    SET @MyUserID = (SELECT SCOPE_IDENTITY()) 

    UPDATE Users 
    SET UserName = @MyUserID 
    WHERE UserID = @MyUserID 
    END 
END TRY 
BEGIN CATCH 
    ROLLBACK TRAN UserInsert 
    RETURN 
END CATCH 
COMMIT TRAN UserInsert 
END 

他のいくつかのポイント: - これは本当に奇妙な要件のように思えます。あなたのデザインを見てみたいかもしれません。 - SCOPE_IDENTITY() issues with parallel query plansにご注意ください。 OUTPUT句は、バグが解決されるまで、現在ではもっと安全です。

+0

"Update ... UserId = SCOPE_IDENTITY()"のように、ローカル変数なしで更新を書き込むことは可能でしょうか? – Andomar

1

SQL Server 2008以降を使用している場合は、この問題を非常に簡単に解決するための新しい機能があります。フィルタリングされたインデックス。フィルターされた索引を使用すると、索引にWHERE条件を入れて、索引がそれらの値を無視するようにすることができます。この場合、一意索引であってもnull UserName値は無視できます。次のように

構文は次のとおりです。また、ユーザー名フィールドにジャンクデータを配置する必要がないことを意味し、この特定の問題を解決するために濾過索引を使用し

CREATE UNIQUE INDEX IX_Users_UserName ON Users (UserName) 
         WHERE UserName is not null 

1

トランザクションでラッピングし、UserNameにspidを使用する方法はありますか。