• ベストアンサー

Null値を無視してユニークにしたい

下記のようなテーブルがあります。 ID  aaa  bbb 10  A01 11 12      B01 13  A02 14  A03  B02 ・IDは,主キー(レコードの登録時に,IDENTITYで自動的に取得) ・aaa,bbbは,任意のタイミングで入力や編集があるが,ユニーク性を保ちたい ・aaa,bbbの入力に関しては,下記のようなテーブルを作って自動採番にしたい Category  Last_No   A     03   B     02 (1)データベース側にて,aaa,bbbにユニークインデックスを設定すると, Null値に関しても重複違反になってしまったのですが, これは,そういうものなのでしょうか? (2)ユニークインデックスが設定できない場合に, Null値以外の値が,ユニークである事を保つためには, どうすれば良いのでしょうか? 自動採番だけでなく,編集も有り得るため,悩んでいます。 (編集は,A01-1のように,枝番を付ける場合が多いです) 以上,どなたかご教示願います。

noname#86170
noname#86170

質問者が選んだベストアンサー

  • ベストアンサー
  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.1

ユニーク制約でNULLを除くことができないのは、リンクページに書かれている通りです。 「PRIMARY KEY 制約とは異なり、UNIQUE 制約は NULL 値を許容できます。ただし、UNIQUE 制約が適用される他の値と同様に、NULL 値も 1 列に 1 つしか使用できません。 」 代替案はありますが、導入可否はテーブルデザインのガイドラインとレスポンス要求の程度により判断してください。 具体的には「スカラーファンクションを1つ作成して、チェック制約で使う」というものです。 CREATE FUNCTION [dbo].[ISUNIQUE](@aaa varchar(5)) RETURNS int AS BEGIN IF (SELECT COUNT(*) FROM TABLE1 WHERE aaa=@aaa)>1 RETURN 0 RETURN 1 END ALTER TABLE TABLE1 ADD CONSTRAINT [CK_aaa] CHECK (dbo.ISUNIQUE(aaa)=1) こんな感じです。 ユニークフィールドが複合であっても、上記の応用で実現はできます。 (チェック制約に使われた関数は、チェック制約を外さない限りDROPできなくなります) 今回のはいけますが、そもそもチェック制約というのはDELETEのときには働かないことは認識しておいてください。 またここまで踏み込めなければ同じことをトリガやるのもありかと思います(トリガは権限があればオフれるのでそこが違いでしょう)。

参考URL:
http://msdn.microsoft.com/ja-jp/library/ms191166(SQL.90).aspx
noname#86170
質問者

お礼

jamshid6様 昨日の質問に引き続き,ご回答いただきましてありがとうございます。 ご回答いただいた内容を試し,aaaフィールドに 重複するレコードが登録出来ないことを確認しました。 ですが,これを下記のように利用しようとしたところで, 躓いてしまいました。 1回目の実行で,aaa=A04のレコードが正常に登録された後, 2回目の実行で,制約違反で発生するエラーをトラップしたいのですが, 「INSERTステートメントはCOLUMN CHECKで,制約'CK_aaa'と矛盾しています。」 とのエラー表示となってしまい,処理が中断してしまいます。 クエリアナライザで,   insert TABLE1 values('A04','B03')   print @@error として,@@errorにて547と返ってくる事を確認しているのですが, どこが間違っているのでしょうか? ●SQL SERVER 2000のストアド CREATE PROCEDURE Strd_Test_Add ( @aaa varchar(5), @bbb varchar(5), @rowcount int output, @err int output ) AS set nocount on begin BEGIN TRANSACTION insert TABLE1 (aaa,bbb) values(@aaa,@bbb) select @rowcount=@@rowcount ,@err=@@error if @err<>0 goto err COMMIT TRANSACTION end return err: ROLLBACK TRANSACTION return GO ●Excel2003のVBA Private Sub btn1_Click() Set dbCN = New ADODB.Connection dbCN.Open "Provider=SQLOLEDB;" _ & "Data Source=*****;" _ & "Initial Catalog=DB_Test;" _ & "User ID=sa;Password=" Set dbCOM = New ADODB.Command dbCOM.ActiveConnection = dbCN dbCOM.CommandType = adCmdStoredProc dbCOM.CommandText = "Strd_Test_Add" dbCOM.Parameters.Refresh dbCOM.Parameters("@aaa") = "A04" dbCOM.Parameters("@bbb") = "B03" dbCOM.Execute MsgBox dbCOM.Parameters("@rowcount").Value _ & vbCrLf & dbCOM.Parameters("@err").Value Set dbCOM = Nothing End Sub

その他の回答 (2)

  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.3

SQL Server 2000だったのですね。 私の認識する限りでは、SQL Server 2005のようにエラーを抑え込むTRY/CATCH構文のようなものは2000にはないので、VBAサイドでOn Error Resume Nextを使ってエラーを抑え込むことになると思います。

noname#86170
質問者

お礼

jamshid6様 度々の回答,ありがとうございます。 On Error Resume Nextにてエラーを回避することにより VBA側でエラー番号を取得できました。

回答No.2

>Null値に関しても重複違反になってしまった SQL Serverの独自仕様になっています。

noname#86170
質問者

お礼

chukenkenkou様 ありがとうございます。

関連するQ&A

  • 'id'を無視して、外部ファイルを読み込むには?

    MySQLでデータベースを作成しています。テーブルを以下のように作成しました。 create table table_name (     id MEDIUMINT NOT NULL AUTO_INCREMENT,     aaa text,     bbb text,     ccc text,     PRIMARY KEY (id) ); そして、以下のようなファイル(/root/file)を読み込みます。(尚、ファイルはLinux上で作成しました。) [/root/file] a1,b1,c1 a2,b2,c2 a3,b3,c3 そして、データベース上で以下のようなコマンドを実行しました。 load data local infile '/root/file' into table table_name fields terminated by ',' lines terminated by '\n'; すると、以下のような結果が得られます。 +----+-----+-----+------+ | id | aaa | bbb | ccc | +----+-----+-----+------+ | a1 | b1 | c1 | NULL | | a2 | b2 | c2 | NULL | | a3 | b3 | c3 | NULL | +----+-----+-----+------+ 以下のようにテーブルを作り直すことなく、 create table table_name (     aaa text,     bbb text,     ccc text,     id MEDIUMINT NOT NULL AUTO_INCREMENT,     PRIMARY KEY (id) ); また、以下のようにファイルを書くことなく、 [/root/file] ,a1,b1,c1 ,a2,b2,c2 ,a3,b3,c3 以下のような結果を出すにはどのようにすればよいのでしょうか。(つまり、自動的に作成される'id'を無視するにはどうすればよいのでしょうか。) +----+-----+-----+-----+ | id | aaa | bbb | ccc | +----+-----+-----+-----+ | 1 | a1 | b1 | c1 | | 2 | a2 | b2 | c2 | | 3 | a3 | b3 | c3 | +----+-----+-----+-----+ よろしくお願い致します。

    • ベストアンサー
    • MySQL
  • テーブル内の一括コピーについて

    SQLServer で テーブルAが下記のようにあり ID name subname 25 AAA NULL 28 BBB NULL 31 CCC NULL subnameの欄にIDの値と全く同じものをいれたいのですが どのようにしたらできるでしょうか? ID name subname 25 AAA 25 28 BBB 28 31 CCC 31 ↑結果的にはこうなってほしいのですが よろしくお願いします。

  • Null同士の結合

    お力貸してください。 [Table111] データA   データB    データC     Name111 Null     1        5         あああ 2       Null      6         いいい 3       4        7         ううう [Table222] データA    データB     データC     Name222 Null      1         5          AAA 2        Null       6          BBB 3        4         7          CCC Table111とtable222をデータAとデータBとデーターCの3つで結合して 新しいテーブルをつくりたいです。 [TableC] データA    データB   データC  Name111   Nam222 Null       1       5      あああ       AAA 2         Null     6      いいい       BBB 3         4       7      ううう       CCC Nullもデーターとして認識させたいのですが、うまくいきません。 できれば、新しくテーブルを作ったりしたくないです。 お知恵をかしてください。よろしくおねがいします。

  • 重複していないレコードの抽出方法について

    下記のテーブルでフィールドAとBの関係で矛盾が生じているID 1と2を抜き出すSQLを必要としております。 AとBを合体させて判断しようと試みましたがダメでした。 ご存知の方ご教示いただけると大変助かります。 【テーブル】 ―――――――――― |ID| A |B| ―――――――――― |1 |AAA|B | |2 |AAA|C | |3 |BBB|D | |4 |BBB|D | |5 |CCC|E | |6 |DDD|F | ―――――――――― よろしくお願いします。

  • NULL行の取得について

    教えてください。 Aはトランザクションテーブルです。 A 列1 列2 1 1 2 NULL 3 2 Bは種別テーブルです。 B 列1 列2 列3 aaa 1 あああ1 aaa 2 あああ2 aaa 3 あああ3 select A.列1 B.列3 from INNER JOIN B ON ( (A.列2 = B.列2 or A.列2 is null) and B.列1 = 'aaa') 上記のSQLを実行すると、 A.列1が2のような、列2がNULLだと、 1 あああ1 2 あああ1 2 あああ2 2 あああ3 3 あああ2 となってしまいます。 望む形としては、 1 あああ1 2 null 3 あああ2 としたいのですが。。。 何が悪いか、教えていただけませんでしょうか。 お願いします。

  • SQLについて教えてください

    お世話になります。 SQLについて教えてください AテーブルとBテーブルからCテーブルを作成したいのですが、 KEYをキーにAテーブルのIDが1で、YYMMが一番新しい項目(最大の項目)を 取得し、Cテーブル作成したいのですが、どのようにするのでしょうか? Aテーブル    Bテーブル   Cテーブル KEY ID yymm   KEY     KEY YYMM AAA 0 200612  AAA     AAA 200611 AAA 1 200611  BBB     BBB 200611 AAA 1 200609 BBB 0 200611 CCC 1 200611

  • AccessにおいてフィールドがNULLの値を0に変換するには

    下記のようなSQLで件数を取得したいと考えています。 テーブルBの件数がNULLの場合、差がNULLになってしまいます。 このような場合、差を0にしたいです。 どのように修正したらよいでしょうか。 SELECT A.ID, (A.件数-B.件数) AS 差 FROM A LEFT JOIN B ON A.ID = B.ID;

  • 抽出条件入力用テキストボックスが空白の場合の抽出条件

    SQL初心者です。 今あるテーブル(TABLE)に | VALUE_A | VALUE_B | VALUE_C | VALUE_D | ----------------------------------------- | 000 | AAA | AAA | AAA | | 001 | AAA | AAA | BBB | | 002 | AAA | BBB | AAA | | 003 | BBB | BBB | BBB | | 004 | BBB | BBB | NULL | のようなデータが入っているとします。 Web上から VALUE_B VALUE_C VALUE_D に対しそれぞれテキストボックス入力フィールドから値を入力し検索を行うようにしたいのです。 [VALUE_B]=AAA [VALUE_C]=AAA [VALUE_D]=AAA と入力されれば VALUE_A:000 を検索結果として出します。 [VALUE_B]=AAA [VALUE_D]=AAA と入力されれば VALUE_A:000 VALUE_A:002 を検索結果として出します。 [VALUE_B]=AAA だけが入力された場合は VALUE_A:001 VALUE_A:002 VALUE_A:003 を検索結果として出します。 つまり、フォームのテキストボックスに入力された条件で抽出し、入力が無い場合は全件抽出を行いたいのです。 この場合、どのようなSQLを組めばよいのかわかりません。ANDやORだけでは対応できないような気がします。Oracleを始めたばかりということもあり、どのような関数を使えばよいのかもわかりません。どなたかご教授いただけませんでしょうか??よろしくお願いします。

  • 分岐SQLを一発のSQLで実現したい

    【データベース:SQLServer2005】 SQLのアドバイスを頂きたいです。 【テーブル】 テーブル名:Table1 フィールド名:種類、キー1、キー2 テーブル名:Table2 フィールド名:種類、キー1、キー2 テーブル名:Table3 フィールド名:種類、キー1、キー2 【データ】 Table1 種類、キー1、キー2 001  AAA  BBB 001  AAA  CCC 001  AAA  DDD Table2 種類、キー1、キー2 002  AAA  BBB 002  AAA  CCC NULL  AAA  DDD Table3 種類、キー1、キー2 NULL  AAA  BBB NULL  AAA  CCC NULL  AAA  DDD これをUNIONで取得します。 種類、キー1、キー2 001  AAA  BBB 001  AAA  CCC 001  AAA  DDD 002  AAA  BBB 002  AAA  CCC NULL  AAA  DDD NULL  AAA  BBB NULL  AAA  CCC 実現したいのは、 1)同種類、キー1、キー2のデータで、 種類にNULLが含まれていたら、NULLのデータは取得しない 2)同種類、キー1、キー2のデータで、 種類にNULLしかないデータは、取得する 001  AAA  BBB 001  AAA  CCC 001  AAA  DDD 002  AAA  BBB 002  AAA  CCC NULL  AAA  DDD →いる NULL  AAA  BBB →いらない NULL  AAA  CCC →いらない ↓結果 001  AAA  CCC 001  AAA  DDD 002  AAA  BBB 002  AAA  CCC NULL  AAA  DDD 上記を実現する為、UNION後のSQLでも構わないので、 一発のSQLで取得する事は可能でしょうか? 有識者の方にご享受頂ければ幸いです。 どうぞ宜しくお願い申し上げます。

  • 最新レコードを抽出し外部結合する方法について

    お世話になります。 現在、最新レコードを抽出し外部結合するSQLを考えているのですが、実現できておりません。 実現できるSQLをご存知の方、いらっしゃいましたら情報を頂けますでしょうか。 # 私の使用しているのは、PostgreSQL8.3となります。 実現したい内容は、以下となります。  1.テーブルAから「名前」でグループ化して最新の「更新日付」のレコードを抽出。  2.1の結果とテーブルBを「名前」で結合。  3.テーブルAの「名前」、「点数」、「更新日付」とテーブルBの「判定」を抽出。    ⇒ただしテーブルAに情報がある場合は、テーブルBの判定結果を「0」にして出力。      テーブルA               テーブルB ----------------------------   -----------------------  名前| 点数| 更新日付       名前 | 判定  ----------------------------   ----------------------- AAA   98   2011/4/1        AAA   0  AAA   60   2011/4/3        BBB   1  BBB   70   2011/4/2        CCC   1  BBB   35   2011/4/4        DDD   1  DDD   98   2011/4/1        EEE   0  EEE   47   2011/4/5         FFF   0  GGG   80   2011/4/6        GGG   1    【出力結果】 ---------------------------------------------  名前 | 点数  | 更新日付 | 判定  --------------------------------------------- AAA    60     2011/4/3      0  BBB    35     2011/4/4     0(1⇒0に変更)  CCC   NULL     NULL       1  DDD    98     2011/4/1     0(1⇒0に変更)  EEE    47     2011/4/5      0  FFF    NULL     NULL       0  GGG    80     2011/4/6     0(1⇒0に変更) お手数お掛け致しますが、ご教示のほどよろしくお願い致します。