web-dev-qa-db-ja.com

SQL Serverに自己参照エントリを挿入する

Personテーブルがあり、created_byテーブル自体のプライマリIDを参照する列。したがって、別の従業員をデータベースに追加するのは従業員である可能性があります。正常に動作します。

ただし、Peopleは自分自身を追加することもできます(サインアップ)。したがって、created_by列は、id列の自動インクリメント値でなければなりません。しかし、その値は明らかに挿入後まで利用できません。

したがって、(a)値をチェックしないように参照を作成する、(b)最初にデフォルト値を追加する、または(c)列をNULL可能にすることができます。すべてのオプションが私には悪いようです。

MySQLの方言はこれを持っています:

SET FOREIGN_KEY_CHECKS = 0;
INSERT INTO EMPLOYEE VALUES('12345','67890'),('67890','12345');
SET FOREIGN_KEY_CHECKS = 1;

...しかし、SQL ServerのT-SQLに似たものを見つけることができませんでした。

3
Remy

主キーにIDを使用しているようです。主キーに柔軟性が必要な場合は、シーケンスを使用することをお勧めします。それはこのようなものになります。

CREATE SEQUENCE SQ_temp AS INT INCREMENT BY 1 START WITH 1

CREATE TABLE Users 
( ID INT PRIMARY KEY DEFAULT NEXT VALUE FOR SQ_temp
, UserName VARCHAR(30)
, createdBy INT REFERENCES Users (ID)
)


INSERT INTO dbo.Users
(
    ID
    , UserName
    , createdBy
)
VALUES
(NEXT VALUE FOR SQ_temp,'User1', NEXT VALUE FOR SQ_temp)
, (NEXT VALUE FOR SQ_temp,'User2', NEXT VALUE FOR SQ_temp)
, (NEXT VALUE FOR SQ_temp,'User3', NEXT VALUE FOR SQ_temp)


SELECT *
FROM dbo.Users AS u
5
SQLing4ever

自己参照エントリをSQLサーバーに挿入する

タイトルごとの一般的な質問については、次のような簡単な挿入で直接循環参照を追加できます

_INSERT node 
       (id , name  , parent_id) 
VALUES (123, 'Test', 123      )
_

すべての新しいデータを考慮して制約が適用されるためです。ステートメントが完了した後にFXが参照する値が存在する限り、すべて順調です。これは、リンクリストに複数の値を挿入するのと同じです。

_INSERT node 
       (id , name   , parent_id) 
VALUES (101, 'Test1', 100      )
     , (102, 'Test2', 101      )
     , (103, 'Test3', 102      )
_

または間接循環参照:

_INSERT node 
       (id , name   , parent_id) 
VALUES (201, 'Test5', 203      )
     , (202, 'Test6', 201      )
     , (203, 'Test7', 202      )
_

したがって、created_by列の値は、id列の自動インクリメントされた値である必要があります

挿入する前に生成されたものがわからないため、これは問題を引き起こします。実際、信頼できる方法で知ることはできません。個々の行を挿入する場合、SCOPE_IDENTITY()を使用して新しい行をすぐに更新できます。

_INSERT node 
       (name  ) 
VALUES ('Test')
-- and now make the circular reference
UPDATE node 
SET    parent_id = SCOPE_IDENTITY()  
WHERE  id        = SCOPE_IDENTITY()
_

上記の例で、_parent_id_が必須の列である場合(DEFAULTなしで_NOT NULL_と宣言されている)、ダミーの一時的な有効を指定する必要があります次のように、最初のINSERTステートメントから除外するのではなく、値:

_INSERT node 
       (name  , parent_id) 
VALUES ('Test', 0        )
-- and now make the circular reference
UPDATE node 
SET    parent_id = SCOPE_IDENTITY()  
WHERE  id        = SCOPE_IDENTITY()
_

複数の行の挿入を処理する場合(説明する可能性は低いが、他の場所では一般的です)、OUTPUT句を使用して、各行に作成されたIDを読み取り、さらに参照できます。現在の質問ではやり過ぎなので、ここでは説明しません。 https://docs.Microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-)を参照してください。 sql 詳細については。

したがって、created_by列の値は、id列の自動インクリメントされた値である必要があります

2012年以降であれば、SQL ServerのSEQUENCEを使用してこれを実行できることがわかります。これは、上記の複数ステートメントのオプションよりも優れたソリューションです。実際の例については、SQLing4everの回答を参照してください。 2012年より前はこの機能は利用できなかったため、SQL Serverの古いインスタンスをサポートする必要がある場合は、この回答のメソッドにフォールバックする必要があります。

6
David Spillett