8

CHECK制約のサブクエリをサポートしているSQLデータベースはありますか?

現在、そして私が知る限り、Oracle、MySQL、およびPostgreSQLはそうではありません。

編集

(最初の回答に基づく明確化。)私は次のようなものを探しています:

CREATE TABLE personnel (
  ...,
department VARCHAR(64) NOT NULL,
salary NUMERIC NOT NULL,
CHECK (salary >= (SELECT MIN(p.salary) FROM payranges p WHERE p.dept = department)
        AND
       salary <= (SELECT MAX(p.salary) FROM payranges p WHERE p.dept = department)
)

アップデート

MSAccessとFirebirdはどちらもこの機能をサポートしています。

4

6 に答える 6

7

Accessデータベースエンジン(ACE、Jetなど)は制約のサブクエリをサポートしますが、エントリレベルの標準SQL-92をサポートしておらず、Accessの制約はMSとAccessチームによってほとんど文書化されていないため、 SQLDBMSCHECKと呼ぶことを躊躇します。CHECK

たとえば、CHECK影響を受ける行ごとにアクセス制約がチェックされることを示すことができます(SQL-92では、SQLステートメントごとにチェックする必要があると指定されています)が、これがバグなのか、参照するドキュメントがないためにわからない機能なのかに。


これは、サブクエリを構成するCHECK制約の非常に単純な例です。フルSQL-92に準拠しており、Accessで適切に機能します。アイデアは、テーブルを最大2行に制限することです(次のSQL DDLにはANSI-92クエリモードが必要です。たとえば、などのADO接続を使用しますAccess.CurrentProject.Connection)。

CREATE TABLE T1 
(
 c INTEGER NOT NULL UNIQUE
);

ALTER TABLE T1 ADD
   CONSTRAINT max_two_rows
      CHECK (
             NOT EXISTS (
                         SELECT 1
                           FROM T1 AS T
                         HAVING COUNT(*) > 2
                        )
            );

ただし、これはSQL-92である別の例であり、Accessで作成できます(一部の有効なCHECKsはAccessで失敗し、マシンを再起動する必要がある恐ろしいクラッシュが発生します:(しかし正しく機能しません。テーブルに正確に2行を許可します(またはゼロ行:空のテーブルに対して制約はテストされません):

CREATE TABLE T2 
( 
 c INTEGER NOT NULL UNIQUE 
);

ALTER TABLE T2 ADD 
   CONSTRAINT exactly_two_rows 
      CHECK ( 
             NOT EXISTS ( 
                         SELECT 1 
                           FROM T2 AS T 
                         HAVING COUNT(*) <> 2 
                        ) 
            );

同じステートメントに2つの行を挿入しようとします(例:テーブルT1に少なくとも1つの行があると仮定):

SELECT DT1.c
  FROM (
        SELECT DISTINCT 1 AS c
          FROM T1
        UNION ALL
        SELECT DISTINCT 2
          FROM T1
       ) AS DT1;

ただし、これによりCHECK噛み付きます。これ(およびさらなるテスト)CHECKは、各行がテーブルに追加された後にがテストされることを意味しますが、SQL-92は、制約がSQLステートメントレベルでテストされることを指定します。

CHECKAccess2010までトリガー機能がなく、頻繁に使用される特定のテーブルには真のキーがないことを考えると、Accessに本当にテーブルレベルの制約があることはそれほど驚くべきことではありません(たとえば、'シーケンス'有効な状態の時間テーブルのキー)。Access2010トリガーには、ステートメントレベルではなく、行レベルでテストされるのと同じバグ/機能があります。

以下は、上記の2つのシナリオを再現するためのVBAです。コピーしてVBA/VB6標準の.basモジュールに貼り付けます(Excelを使用するなど)。参照は必要ありません。tempフォルダーに新しい.mdbを作成し、制約が機能する/機能しないことを示すテーブル、データ、およびテストを作成します(ヒント:ブレークポイントを設定し、コードをステップ実行し、コメントを読みます)。

Sub AccessCheckSubqueryButProblem()

  On Error Resume Next
  Kill Environ$("temp") & "\DropMe.mdb"
  On Error GoTo 0

  Dim cat
  Set cat = CreateObject("ADOX.Catalog")
  With cat
    .Create _
        "Provider=Microsoft.Jet.OLEDB.4.0;" & _
        "Data Source=" & _
        Environ$("temp") & "\DropMe.mdb"
    With .ActiveConnection

      Dim Sql As String

      Sql = _
      "CREATE TABLE T1 " & vbCr & _
      "( " & vbCr & _
      " c INTEGER NOT NULL UNIQUE " & vbCr & _
      ");"
      .Execute Sql

      Sql = _
      "ALTER TABLE T1 ADD " & vbCr & _
      "   CONSTRAINT max_two_rows " & vbCr & _
      "      CHECK ( " & vbCr & _
      "             NOT EXISTS ( " & vbCr & _
      "                         SELECT 1 " & vbCr & _
      "                           FROM T1 AS T " & vbCr & _
      "                         HAVING COUNT(*) > 2 " & vbCr & _
      "                        ) " & vbCr & _
      "            );"
      .Execute Sql

      Sql = _
      "INSERT INTO T1 (c) VALUES (1);"
      .Execute Sql

      Sql = _
      "INSERT INTO T1 (c) VALUES (2);"
      .Execute Sql

      ' The third row should (and does)
      ' cause the CHECK to bite
      On Error Resume Next
      Sql = _
      "INSERT INTO T1 (c) VALUES (3);"
      .Execute Sql
      MsgBox Err.Description
      On Error GoTo 0

      Sql = _
      "CREATE TABLE T2 " & vbCr & _
      "( " & vbCr & _
      " c INTEGER NOT NULL UNIQUE " & vbCr & _
      ");"
      .Execute Sql

      Sql = _
      "ALTER TABLE T2 ADD " & vbCr & _
      "   CONSTRAINT exactly_two_rows " & vbCr & _
      "      CHECK ( " & vbCr & _
      "             NOT EXISTS ( " & vbCr & _
      "                         SELECT 1 " & vbCr & _
      "                           FROM T2 AS T " & vbCr & _
      "                         HAVING COUNT(*) <> 2 " & vbCr & _
      "                        ) " & vbCr & _
      "            );"
      .Execute Sql

      ' INSERTing two rows in the same SQL statement
      ' should succeed according to SQL-92
      ' but fails (and we have no docs from MS
      ' to indicate whether this is a bug/feature)
      On Error Resume Next
      Sql = _
      "INSERT INTO T2 " & vbCr & _
      "   SELECT c " & vbCr & _
      "     FROM T1;"
      .Execute Sql
      MsgBox Err.Description
      On Error GoTo 0


    End With
    Set .ActiveConnection = Nothing
  End With
End Sub
于 2011-06-01T05:42:13.447 に答える
4

Firebirdのドキュメントには、CHECK制約でのサブクエリが許可されていると記載されています。

于 2012-03-29T00:16:19.007 に答える
2

SQL Server 2000+では、クエリを含むUDFが許可されています。サブクエリを直接使用することはできません。

ただし、高負荷では同時ではありません

于 2011-06-01T04:43:21.963 に答える
1

H2は、制約内のサブクエリもサポートします。Psqlモードでも:P

MariaDBは、制約としてもサポートしていないようです。

ALTER TABLE Table_1 ADD CONSTRAINT constraint_1 
CHECK (column_1 > (SELECT MAX(column_2) FROM Table_2) NOT DEFERRABLE;

重要この本はSQL-99標準に関するものであるため、この本のページや他のページの内容は、MariaDBに直接適用されない場合があります。ナビゲーションバーを使用して本をナビゲートします。

この種のことはかつては違法でしたが、SQLの最新のバリエーションでは、テーブル間の制約参照がときどき表示されます。

参考までに、これはMariaDBにチェック制約を実装するためのチケットです。2015年7月23日現在、まだ「オープン」状態です。

于 2015-07-22T07:01:56.403 に答える
0

TRIGGERがあなたが言及した各データベースで機能することはかなり確実であり、制約を解決するためのより多くの「エルボールーム」が得られます。

于 2011-06-01T03:30:31.173 に答える
-3

SQLServerはそれをサポートしています次のリンクで貴重な情報を見つけることができます

http://www.craigsmullins.com/sql_1298.htm

POSTGRESQLもそれをサポートしていると彼らは言う

http://developer.postgresql.org/pgdocs/postgres/ddl-constraints.html

DB2はCHECK制約をサポートします

http://www.ibm.com/developerworks/data/library/techarticle/dm-0401melnyk/

于 2011-06-01T03:19:49.787 に答える