SQL Server:単一の行を含むようにテーブルを制約する方法は?


81

アプリケーションの構成テーブルに単一の行を格納したいと思います。このテーブルに含めることができる行は1つだけにするように強制したいと思います。

単一行の制約を適用する最も簡単な方法は何ですか?


(Name, Value)Nameに主キーを持つ列を持つテーブルを使用してみませんか。そうすればselect Value from Table where Name = ?、行が返されないか、1行が返されることを確実に確認できます。
a'r 2010年

2
ここでSQLが最善の解決策かどうかはわかりません。おそらく、単純なxmlファイルの方が構成に適しています。私は、構成!=データとSQLがデータ用に作成されたと思っていました。
レミブルガレル2010年

2
@ ar-たとえば整数を読み取ることを期待しているときに、それがひどく間違っているのを見てきました。値の列に正しくフォーマットされていない値が表示されます。
damien_The_Unbeliever 2010年

@Damien_The_Unbelieverなぜそれが起こるのでしょうか?Name?に存在しない値を指定したため
ヌーメノン2018年

1
@ Noumenon-私のコメントはarsのコメントへの応答であったことに注意してください。問題は、名前と値のペアを格納するだけの場合、値は文字列である必要があり、データベースで検証を強制する手段がないことです。(OPが必要とするように)設定ごとに個別のを持つ単一行テーブルを使用する場合、チェック制約を介して各構成設定の検証を簡単に実施できます。
damien_The_Unbeliever 2018年

回答:


97

列の1つに1つの値のみを含めることができることを確認してから、それを主キーにします(または一意性制約を適用します)。

CREATE TABLE T1(
    Lock char(1) not null,
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

私はさまざまなデータベースにこれらのテーブルをいくつか持っていますが、主に構成を保存するためのものです。構成アイテムがintである必要がある場合、DBからintを読み取るだけになることを知っていると、はるかに便利です。


2
+1。これは、Celkoが「SQLforSmarties」の補助定数テーブルに使用するアプローチです
Martin Smith

これは簡単です。ありがとう。
マーティン

+1:興味深い解決策。私はこれまで見たことがなかったので、共有してくれてありがとう。いつも道、方法を知っていれば簡単....
John Sansom 2010年

考え直すためのフォローアップの質問があります。このテーブルの主キーは何ですか?:)
nvogel 2010

2
@ BZ-cdtはcomp.databases.theory、usenetグループ(Googleグループで表示)の省略形で、最近はあまり読んでいないことを認めています。SQLよりもリレーショナル理論に重点を置いていましたが、dportas / sqlvogelも同じグループに頻繁にアクセスしていることを偶然知っていました。TTMは、SQLではなく関係理論について(再び)話している優れた本であるThe ThirdManifestoへ参照でした。
damien_The_Unbeliever 2013年

53

私は通常、ダミアンのアプローチを使用します。これは常に私にとってうまく機能していますが、1つ追加します。

CREATE TABLE T1(
    Lock char(1) not null DEFAULT 'X',
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

「DEFAULT'X '」を追加すると、Lock列を処理する必要がなくなり、テーブルを初めてロードするときにどちらがロック値であったかを覚えておく必要がなくなります。


4
デフォルトの制約にも名前を付ける必要があります。そうしないと、自動生成された紛らわしい名前が付けられます。Lock char(1) not null CONSTRAINT DF_T1_Lock DEFAULT 'X'
David S.

1
さらに、デフォルト値を「X」以外にする必要があります。私は自分の文字列を長くしましたが、2番目の行を挿入しようとすると、これがエラーメッセージになります:PRIMARYKEY制約 'PK_RestrictToOneRow'の違反。オブジェクト 'dbo.1ROWTABLE'に重複するキーを挿入できません。重複するキー値は(このテーブルは1つの行にロックされています)です。
GeoffGriswald19年

14

この戦略を再考することをお勧めします。同様の状況で、履歴情報のために古い構成行をそのままにしておくことは非常に貴重であることがよくあります。

これを行うには、実際には追加の列creation_date_time(挿入または更新の日付/時刻)と、現在の日付/時刻を正しく入力する挿入または挿入/更新トリガーがあります。

次に、現在の構成を取得するには、次のようなものを使用します。

select * from config_table order by creation_date_time desc fetch first row only

(DBMSフレーバーによって異なります)。

そうすれば、リカバリの目的で履歴を維持することができ(テーブルが大きくなりすぎた場合はクリーンアップ手順を開始できますが、これは起こりそうにありません)、最新の構成で作業することができます。


+1:あなたの言っていることを聞きましたが、変更の履歴を別々の監査テーブルに記録することを好みます。
マーティン

+1:監査証跡を実装するという興味深いアイデアを共有してくれました。
John Sansom 2010年

いいね。JustSELECT TOP 1 ... ORDER BY creation_date_time DESC
Baodad 2016

5

INSTEAD OF Triggerを実装して、データベース内でこのタイプのビジネスロジックを適用できます。

トリガーには、レコードがテーブルにすでに存在するかどうかを確認するロジックを含めることができます。存在する場合は、挿入をロールバックします。

さて、全体像を見てみると、おそらく構成ファイルや環境変数など、この情報を保存するための代替のより適切な方法があるのではないかと思います。


+ 1-トリガーがどのように機能するかを確認できます。おそらくそのアプローチにフォールバックしますが、Damienの単純な制約が好きです。構成ファイルに属する構成データのタイプとDBに属する構成データについて興味深い議論があります。この場合、DBが正しい場所だと思います。間違いなく私はこれを後悔するために生きます... :-)
マーティン

2

IsActiveという名前の主キーにビットフィールドを使用します。したがって、最大2つの行があり、有効な行を取得するためのSQLは次のとおりです。テーブルの名前がSettingsの場合、IsActive = 1であるSettingsから*を選択します。


2

これは、YまたはN(たとえば、アプリケーションのロック状態)を保持する1行のみを含むことができるロックタイプのテーブルに対して私が思いついた解決策です。

1列のテーブルを作成します。YまたはNのみを入力できるように、1つの列にチェック制約を設定しました。(または1または0、または何でも)

「通常」の状態でテーブルに1行を挿入します(たとえば、Nはロックされていないことを意味します)

次に、SIGNAL(DB2)、RAISERROR(SQL Server)、またはRAISE_APPLICATION_ERROR(Oracle)しかないテーブルにINSERTトリガーを作成します。これにより、アプリケーションコードはテーブルを更新できますが、INSERTは失敗します。

DB2の例:

create table PRICE_LIST_LOCK
(
    LOCKED_YN       char(1)   not null  
        constraint PRICE_LIST_LOCK_YN_CK  check (LOCKED_YN in ('Y', 'N') )
);
--- do this insert when creating the table
insert into PRICE_LIST_LOCK
values ('N');

--- once there is one row in the table, create this trigger
CREATE TRIGGER ONLY_ONE_ROW_IN_PRICE_LIST_LOCK
   NO CASCADE 
   BEFORE INSERT ON PRICE_LIST_LOCK
   FOR EACH ROW
   SIGNAL SQLSTATE '81000'  -- arbitrary user-defined value
     SET MESSAGE_TEXT='Only one row is allowed in this table';

私のために働きます。


2

古い質問ですが、小さな列タイプのIDENTITY(MAX、1)を使用するのはどうですか?

CREATE TABLE [dbo].[Config](
[ID] [tinyint] IDENTITY(255,1) NOT NULL,
[Config1] [nvarchar](max) NOT NULL,
[Config2] [nvarchar](max) NOT NULL

SET IDENTITY_INSERTを使用して、別の行を追加できます。
Razvan Socol 2018年

1

テーブルの挿入アクションにトリガーを書き込むことができます。誰かがテーブルに新しい行を挿入しようとするたびに、挿入トリガーコードの最新の行を削除するロジックを実行します。



-1

ここでは、データベースへの最初のエントリ後に同じになる非表示の値を作成することもできます。例:Student Table:Id:int firstname:charここで、入力ボックスで、制限するid列に同じ値を指定する必要があります。主キーの制約のためにlockbla blaを書き込む以外の最初のエントリの後のように、したがって永久に1行しかありません。お役に立てれば!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.