web-dev-qa-db-ja.com

2つの異なるテーブルで2つの同一の主キーをリンクすることに問題はありますか?

enter image description here

ここでわかるように、OrderInfoOrderNumberには関係セットがあります。しかし、私はどんな種類かわかりません。 関係を設定することを望んでいたので、OrderNumberを削除すると、OrderInfo内の対応するレコードがカスケード削除されますが、許可されません。それは私にこの厄介なを与える '

iD列で削除をカスケードできません

エラーなので、カスケード削除を削除した後、適切に保存しました。キーとキーの意味がわかりませんが、無限へのキーは1対多であると知っていますか?

4
user18139

モデルはOrderNumberOrderInfoの間の1対1の関係であるように見えます。OrderInfo.OrderIDOrderInfo主キーおよび外部キー参照としてOrderNumber.OrderID

エラーメッセージは、OrderInfo.OrderIDIDENTITY列として定義したことを示しています。 IDENTITYであってはなりません。関連するOrderID行を挿入するときに、関連するOrderNumber行から割り当てられたOrderInfo値を使用して、外部キーの関係を維持する必要があります。これにより、DELETE CASCADEを指定できるようになります。

7
Dan Guzman

OrderInfo.OrderIDOrderNumber.OrderIDを参照する外部キーにしたい場合は、INTEGER IDENTITYではなくINTEGERとして宣言する必要があります。 IDの場合、OrderIDへの挿入後に取得した対応するOrderNumberの実際の値をそれに割り当てることができませんでした。

つまり、次のようにテーブルを宣言する必要があります。

CREATE TABLE Customer
(
    CustomerID integer IDENTITY(1,1) PRIMARY KEY,
    FirstName varchar(100),
    LastName varchar(100)
) ;

CREATE TABLE Consultants
(
    ConsultantID integer IDENTITY(1,1) PRIMARY KEY,
    EmployeeID integer /* REFERENCES Employees(EmployeeID) */
) ;

CREATE TABLE OrderNumber
(
    OrderID integer IDENTITY(1,1) PRIMARY KEY,
    CustomerID integer REFERENCES Customer(CustomerID) ON DELETE NO ACTION,  /* Referenced CustomerID cannot be deleted */
    ConsultantID integer REFERENCES Consultants(ConsultantID) ON DELETE NO ACTION  /* Referenced ConsultantID cannot be deleted */
) ;

CREATE TABLE OrderInfo
(
    OrderID integer NOT NULL REFERENCES OrderNumber(OrderID) ON DELETE CASCADE,
    /* My assumption: one order can have several items 
       If that were not the case, the following column could be ommitted.
       Otherwise, just put all the [OrderInfo] columns in [OrderNumber] table,
       and just call it [Order].
    */
    SomeOtherColumnSuchAsLineNumber integer NOT NULL,

    /* The actual PK should be a composite */
    PRIMARY KEY (OrderID, SomeOtherColumnSuchAsLineNumber),

    /* Rest of columns */
    Cost decimal(12,2),
    Description varchar(max)
) ;

-- etc.

顧客、コンサルタント、および2つの注文を挿入し、それぞれ2つのOrderInfoを使用します(注文には複数のアイテムが含まれると想定し、それらを並べ替えるために追加の列を追加しました)。

INSERT INTO Customer(FirstName, LastName) 
OUTPUT inserted.CustomerID
VALUES('John', 'Doe') ;
GO
 | CustomerID | 
 | ---------:| 
 | 1 | 
INSERT INTO Consultants(EmployeeID) 
OUTPUT inserted.ConsultantID
VALUES (1), (2);
GO
 | ConsultantID | 
 | -----------:| 
 | 1 | 
 | 2 | 
INSERT INTO OrderNumber(CustomerID, ConsultantID)
OUTPUT inserted.OrderID
VALUES (1,1), (1,2) ;
GO
 | OrderID | 
 | ------:| 
 | 1 | 
 | 2 | 
INSERT INTO OrderInfo
    (OrderID, SomeOtherColumnSuchAsLineNumber, Cost, Description)
VALUES
    (1, 1, 100.00, 'Item costing 100.00'),
    (1, 2,  99.99, 'Item costing  99.99'),
    (2, 1, 200.00, 'Item costing 200.00'),
    (2, 2, 199.99, 'Item costing 199.99') ;
GO
 4行が影響を受けました

この時点で、OrderInfoにfor行がある場合:

SELECT
    *  -- Don't do this in production, just in demo
FROM
    OrderInfo
ORDER BY
    OrderInfo.OrderID, OrderInfo.SomeOtherColumnSuchAsLineNumber ;
GO
 OrderID | SomeOtherColumnSuchAsLineNumber |コスト|説明
 ------:| ------------------------------:| :-- :------------------ 
 1 | 1 | 100.00 |アイテムの価格は100.00 
 1 | 2 | 99.99 |アイテムの価格99.99 
 2 | 1 | 200.00 |アイテムの価格は200.00 
 2 | 2 | 199.99 | 199.99円のアイテム

OrderNumberから1行削除すると、変更はOrderInfoに反映されます

DELETE FROM
    OrderNumber
WHERE
    OrderID = 2;
GO
 1行が影響を受けました
-- We deleted from OrderNumber OrderID = 2, it won't appear here
SELECT
    *  -- Don't do this in production, just in demo
FROM
    OrderInfo
ORDER BY
    OrderInfo.OrderID, OrderInfo.SomeOtherColumnSuchAsLineNumber ;
GO
 OrderID | SomeOtherColumnSuchAsLineNumber |コスト|説明
 ------:| ------------------------------:| :----- | :------------------ 
 1 | 1 | 100.00 |アイテムの価格は100.00 
 1 | 2 | 99.99 |アイテムの価格は99.99 

dbfiddleですべてを確認できます---(ここ

7
joanolo

このエラーを回避する方法について心配する前に、おそらくこれは技術的な問題ではなく、論理的な問題であると考えてください。データモデルを見て、なぜ最初にOrderInfoOrderNumberを分割しているのか疑問に思います。それらが本当に1対1である場合、それらを分割することによって何が得られますか? CostDescriptionがなく、これらの2つの列にNULLsが含まれないように正規化している場合がありますか?すでに表示されているよりも多くのフィールドがないと仮定します– OrderIDConsultantIDCustomerIDOrderInfo、およびOrderNumber –次に、最も可能性が高い(つまり、全体的な要件についての詳細がわからない場合)これらのフィールドを単一のOrderInfoに統合する方がはるかに良いでしょうテーブル、およびそれらのフィールドの1つ以上がNULLを受け入れる必要がある場合は、そのようにします。

もちろん、論理エンティティを複数のテーブルに分割するのに有効な状況があります(例については、次のDBA.SEの質問に対する私の回答を参照してください: SQL Server 2014圧縮と最大行サイズ )。ただし、この状況は(今のところ)それらの1つではないようです。

コメントで、1対1の関係である他の同様の場所があると述べました

それらの両方が同じ列と同じ名前で

そして、どちらがIDENTITYを持っているべきで、どれが持っていないべきかを決定する方法を疑問に思っていました。これは、これらのテーブルに戻って確認し、本当に分離する必要があるのか​​、それとも統合する必要があるのか​​を検討する良い機会だと思います。本当に別のテーブルとして保持する必要がある場合、関連するテーブルのセットがすべて同じ論理エンティティのプロパティである場合、1つだけ(メインテーブルまたはプライマリテーブルと見なされる方)にIDENTITY(これは上記の私のリンクされた回答に示されているものです)。しかし、それらが別個のエンティティーである場合、それらはcanそれぞれに独自のIDENTITYがあります。


関連するメモで、DepartmentテーブルのPKがEmployeeIDであるのは奇妙です。代わりにDepartmentIDにする必要がありますか?

4
Solomon Rutzky

異なるテーブルの2つの同一の主キーをリンクすることに問題はありませんが、データ型がIDとして宣言されている場合に問題が発生します。

一部のフィールドをIDとして宣言すると、値は自動的にインクリメントされ、提供されている場合はシードによって決定されます。値が同期している場合でも、Danによって指摘されているように、SQLサーバーではこれを続行できません。

INTを使用すれば問題ありません。

1