0

投稿に関連する追加の質問があります: データベースの複合主キー

そこの投稿をチェックしてください(そうでない場合は、繰り返す必要があります)。

ここで私の質問は次のとおりです: ID の自動インクリメントを主キーとして使用する場合 (受け入れて、このキーを介して現在のテーブルを再度参照できるようにするため)、User_ID と Admin_ID (両方の FK) の組み合わせができることをどのように保証できますか?挿入時に一度だけ存在しますか (一意ですか)? これは多対多の関係です。
フロントエンドのプログラミング(既存のレコードを選択してチェック)で行うこともできますが、私の感覚では、これは最善の方法ではなく、バックエンドに直接制限を加えることができるのではないかと考えています。

論理的には FK を主キーに追加しますが、その後、複合キーに戻ります。これは、使用しないように一般的にアドバイスされたものです。
これを行う適切な方法は何ですか?

ご協力いただきありがとうございます。

4

4 に答える 4

3

User_ID と Admin_ID (両方の FK) の組み合わせが、挿入時に 1 回しか存在しない (一意である) ことを保証するにはどうすればよいですか?

複合キーを作成します。

フロントエンドのプログラミングで行うことができます(selectによる既存のレコードのチェック)

あなたがテーブルにアクセスする唯一のクライアントでない限り、それはできませんでした。1

実際の並行環境では、SELECT の、INSERT の前に別のトランザクションが (挿入しようとしている値と同じ値を) 挿入したかどうかを知ることはできません。

また、データベースにアクセスするのが自分だけだったとしても、SELECT を効率的に実行するにはインデックスが必要です。では、なぜ DBMS がこのインデックスをキーとして利用できるようにしないのでしょうか?

論理的には FK を主キーに追加しますが、その後、複合キーに戻ります。これは、使用しないように一般的にアドバイスされたものです。

間違ったアドバイス。列または列の組み合わせを一意にする必要がある場合は、キーを作成する必要があります。2別の (代理) キーがあるからといって、データの正確性を強制するキーの作成をスキップすることはできません。

通常、サロゲートは自然キーを置き換えることはできず、追加することしかできません。3したがって、問題は次のようになります: サロゲートの追加のオーバーヘッドはそれだけの価値がありますか? ある場合もあれば、そうでない場合もありますが、ここには明確なルールはありません。


1または、テーブル全体をロックして、プロセスのスケーラビリティを破壊しようとしています。

2ただし、必ずしもprimaryである必要はありません。

3彼らが通常「置き換える」のは、主キーとしての自然キーの役割ですが、自然キーは引き続き代替キーとして存続します。

于 2012-09-13T18:33:59.813 に答える
1

次の (架空の) スキーマを検討してください。「チェス盤」テーブルに代理キーを追加しますか? {xxx,yyy,pc} の値は、「制限された」ドメインまたは PK+FK 制約によって制約されています。

どのような場合に代理キーを追加するとよいでしょうか ({xxx,yyy} の場合に役立ちますか?

(追加の制約 (例: 色ごとにキングは 1 人まで...) が実際のチェス ゲームには必要であり、ビジネス ルール (有効な動きなど...) は "アプリケーションロジック」とにかく)

-- this is Postgres-specific:
-- create a schema to play in
DROP SCHEMA chess CASCADE ;
CREATE SCHEMA chess ;
SET search_path='chess' ;

        -- Domain with only values A-H to three allowed.
CREATE DOMAIN chess_column
        AS CHAR(1) NOT NULL
        check (value >= 'A' AND value <= 'H')
        ;
        -- Domain with only values 1-8 allowed.
CREATE DOMAIN chess_row
        AS INTEGER NOT NULL
        check (value >= 1 AND value <= 8)
        ;
        -- Table with only valid pieces
CREATE TABLE chess_piece
        ( id INTEGER NOT NULL PRIMARY KEY
        , pname varchar
        ) ;
INSERT INTO chess_piece(id,pname) VALUES
 ( -6, 'Black King' ) , ( -5, 'Black Queen' ) , ( -4, 'Black Rook' )
, ( -3, 'Black Bishop' ) , ( -2, 'Black Knight' ) , ( -1, 'Black Pawn' )
, ( 6, 'White King' ) , ( 5, 'White Queen' ) , ( 4, 'White Rook' )
, ( 3, 'White Bishop' ) , ( 2, 'White Knight' ) , ( 1, 'White Pawn' )
        ;

CREATE TABLE chessboard
        ( xxx chess_column
        , yyy chess_row
        , pc INTEGER NOT NULL REFERENCES chess_piece(id)
        , PRIMARY KEY (xxx,yyy)
        );
        -- Too lazy to enter the entire board
        -- ; only put a White Pawn at E2
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'E', 2, p.id
FROM chess_piece p
WHERE p.pname = 'White Pawn';
        ;
        -- Shift the pawn
UPDATE chessboard b
SET yyy = 4
FROM chess_piece p
WHERE b.pc = p.id
AND p.pname = 'White Pawn';
AND b.xxx = 'E' AND b.yyy = 2
        ;
        -- Try to put a piece outside the board
\echo Try put a piece outside the board
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'I', 2, p.id
FROM chess_piece p
WHERE p.pname = 'Black Pawn';
        ;
        -- add a non-existing piece
\echo add a non-existing piece
INSERT INTO chessboard(xxx,yyy,pc)
VALUES( 'H', 1, 42)
        ;
        -- Position is already occupied
\echo Position is already occupied
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'E', 4, p.id
FROM chess_piece p
WHERE p.pname = 'Black Pawn';
        ;
于 2012-09-14T00:28:54.467 に答える
1

私は複合キーに行きます

自動インクリメントの主キーが本当に必要な場合は、2 つの外部キー列に一意のインデックスを作成します。

補足: 複合キーを使用する利点は、Entity Framework などの ORM ツールを使用すると、自動的に多対多の関係として認識され、追加の交差テーブルが単なる関係に抽象化されることです。

于 2012-09-13T13:17:43.133 に答える
0

IDでどうぞ。他のページの回答に強く同意します。素早くダーティなアプリケーションの場合は、複合キーで十分です。ただし、レポートに使用される静的なテーブルでない限り、通常、作成する新しいテーブルには自動インクリメントされた ID を入れます。

あなたの特定の質問について、私がすぐに思いつくことができる答えが少なくとも4つあります。

  1. 2 つのフィールドが重複しないように制約を実装します。
  2. 2 つの列に一意のインデックスを作成します。
  3. テーブルにトリガーを実装して、重複をチェックします。
  4. データの有効性をチェックするストアド プロシージャを介して挿入を行います。

私の好みは、(1) または (2) と組み合わせて、(4) です。ストアド プロシージャを使用して挿入を制御すると、特に問題をログに記録したりデバッグしたりしたい場合に、柔軟性が大幅に向上することがわかりました。とは言っても、私は通常、オーバーヘッドの削減が最重要となる大量のトランザクション システムを扱っているわけではありません。

他の回答で見逃された自動インクリメントIDには1つの利点があります。次のクエリ:

select *
from t
order by 1 desc

id が最初の列であると仮定して、最近追加されたレコードを返します (すべてのテーブルにあるように)。ID を使用するには、最近挿入されたレコードを表示する機能だけで十分です。

于 2012-09-13T14:59:16.013 に答える