11

しばらく前に、 CJ Dateの著書SQL and Relational Theoryを読んでいました。著者は、SQL の 3 値論理 (3VL) を批判したことで有名です。1)

著者は、SQL で 3VL を避けるべき理由についていくつかの強力な点を述べていますが、null 許容列が許可されていない場合にデータベース モデルがどのようになるかについては概説していません。私はこれについて少し考え、次の解決策を考え出しました。他のデザインオプションを見逃した場合は、それらについて聞きたいです!

1) SQL の 3VL に対する Date の批判も同様に批判されています。Claude Rubinsonによるこの論文を参照してください(CJ Date による元の批判を含みます)。


表の例:

例として、1 つの null 許容列 ( DateOfBirth)がある次のテーブルを取り上げます。

#  +-------------------------------------------+
#  |                   People                  |
#  +------------+--------------+---------------+
#  |  PersonID  |  Name        |  DateOfBirth  |
#  +============+--------------+---------------+
#  |  1         |  Banana Man  |  NULL         |
#  +------------+--------------+---------------+

オプション 1:NULLフラグとデフォルト値によるエミュレート:

列を null 可能にする代わりに、任意のデフォルト値が指定されます (例: 1900-01-01)。追加のBOOLEAN列では、値DateOfBirthを単に無視するか、実際にデータが含まれているかを指定します。

#  +------------------------------------------------------------------+
#  |                              People'                             |
#  +------------+--------------+----------------------+---------------+
#  |  PersonID  |  Name        |  IsDateOfBirthKnown  |  DateOfBirth  |
#  +============+--------------+----------------------+---------------+
#  |  1         |  Banana Man  |  FALSE               |  1900-01-01   |
#  +------------+--------------+----------------------+---------------+

オプション 2: null 許容列を別のテーブルに変換する:

NULL 可能列は、新しいテーブル ( ) に置き換えられますDatesOfBirth。レコードにその列のデータがない場合、新しいテーブルにはレコードがありません。

#  +---------------------------+ 1    0..1 +----------------------------+
#  |         People'           | <-------> |         DatesOfBirth       |
#  +------------+--------------+           +------------+---------------+
#  |  PersonID  |  Name        |           |  PersonID  |  DateOfBirth  |
#  +============+--------------+           +============+---------------+
#  |  1         |  Banana Man  |
#  +------------+--------------+

これはより良い解決策のように思えますが、1 つのクエリで多くのテーブルを結合する必要がある可能性があります。OUTER JOINs は許可されないため (結果セットに導入さNULLれるため)、必要なすべてのデータを以前のように単一のクエリだけでフェッチすることはできなくなりました。


質問: 他に排除するためのオプションはありますかNULL(ある場合、それは何ですか)?

4

7 に答える 7

5

私は、Date の同僚である Hugh Darwenがこの問題について優れたプレゼンテーション「NULL を使用せずに不足している情報を処理する方法」で議論しているのを見ました。

彼の解決策は、2 番目のアプローチの変形です。これは第 6 正規形であり、生年月日と不明な識別子の両方を保持するテーブルがあります。

#  +-----------------------------+ 1    0..1 +----------------------------+
#  |         People'             | <-------> |         DatesOfBirth       |
#  +------------+----------------+           +------------+---------------+
#  |  PersonID  |  Name          |           |  PersonID  |  DateOfBirth  |
#  +============+----------------+           +============+---------------+
#  |  1         |  Banana Man    |           ! 2          | 20-MAY-1991   |
#  |  2         |  Satsuma Girl  |           +------------+---------------+
#  +------------+----------------+
#                                  1    0..1 +------------+
#                                  <-------> | DobUnknown |
#                                            +------------+
#                                            |  PersonID  |
#                                            +============+
#                                            | 1          |
#                                            +------------+

People から選択するには、定型文を含む 3 つのテーブルすべてを結合して、不明な生年月日を示す必要があります。

もちろん、これはやや理論的なものです。最近の SQL の状態は、これらすべてを処理するにはまだ十分に進んでいません。Hugh のプレゼンテーションは、これらの欠点をカバーしています。彼が言及していることの 1 つは、完全には正しくありません。たとえば、Oracle の INSERT ALL 構文など、SQL の一部のフレーバーは複数の代入をサポートしています。

于 2010-06-20T19:47:43.093 に答える
3

オプション 2 を選択することをお勧めします。Chris Date もそうだと確信しています。基本的に、あなたが行っているのは6NFに完全に正規化するためです。これは、 Date が共同で. 私は、不足している情報の取り扱いに関する推奨されたダーウェンの論文を支持します。

OUTER JOIN は許可されないため (結果セットに NULL が導入されるため)、以前のように単一のクエリだけで必要なすべてのデータをフェッチできなくなる可能性があります。

...これは事実ではありませんが、外部結合の問題がダーウェンの論文で明示的に言及されていないことに同意します。それは私が欲しかった唯一のことでした。明確な答えは、伊達の別の本にあるかもしれません…</p>

最初に、Date と Darwen 自身の真のリレーショナル言語であるチュートリアル Dには、自然結合という結合タイプが 1 つしかないことに注意してください。その理由は、実際に必要な結合タイプは 1 つだけだからです。

私がほのめかした日付の本は、優れたSQL and Relational Theory: How to Write Accurate SQL Codeです:

4.6: 外部結合に関する注意: 「関係的に言えば、[外部結合は] できごとの結婚のようなものです: それはテーブルを一種の結合に強制します。そうです、結合ではなく結合を意味します。問題のテーブルが失敗した場合でも。ユニオンの通常の要件に準拠しています...実際には、ユニオンを実行する前にテーブルの一方または両方に null を埋め込むことでこれを行い、最終的にこれらの通常の要件に準拠させます。 null の代わりに適切な値を使用してはいけません

あなたの例とデフォルト値「1900-01-01」を「パディング」として使用すると、外部結合の代替は次のようになります。

SELECT p.PersonID, p.Name, b.DateOfBirth
  FROM Person AS p
       INNER JOIN BirthDate AS b
          ON p.PersonID = b.PersonID
UNION
SELECT p.PersonID, p.Name, '1900-01-01' AS DateOfBirth
  FROM Person AS p
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM BirthDate AS b
                    WHERE p.PersonID = b.PersonID
                  );

Darwen の論文では 2 つの明示的なテーブル、たとえばBirthDateとが散文BirthDateKnownされていますが、SQL はそれほど違いはありません。たとえば、上記BirthDateKnownとの半違いの代わりにへの半結合がBirthDateあります。

上記の使用JOININNER JOINは、標準 SQL-92が実際の SQL 製品に広く実装されていないという理由だけに注意してください (引用を見つけることはできませんが、IIRC ダーウェンは後者の 2 つを標準に組み込むことに大きく関与していました) NATURAL JOINUNION CORRESPONDING

さらに、上記の構文は、一般的に SQL が長ったらしいという理由だけで、長ったらしく見えることに注意してください。純粋な関係代数では、(疑似コード) のようになります。

Person JOIN BirthDate UNION Person NOT MATCHING BirthDate ADD '1900-01-01' AS DateOfBirth;
于 2011-09-07T11:28:22.700 に答える
1

私は読んだことはありませんが、Hugh Darwen と CJ Date が運営するサード マニフェストの Web サイトに、S-by-C を使用して不足している情報を処理する方法という記事があります。これは CJ Date が書いたものではありませんが、その Web サイトの記事の 1 つなので、おそらく彼の意見に似ていると思います。

于 2010-06-20T16:12:58.337 に答える
0

nullを使用して、出力で削除することもできますCOALESCE

SELECT personid  /*primary key, will never be null here*/
       , COALESCE(name, 'no name') as name
       , COALESCE(birthdate,'no date') as birthdate
FROM people

すべてのデータベースがCOALESCEをサポートしているわけではありませんが、ほとんどすべてのデータベースに
IFNULL(arg1, arg2)、同じことを行うフォールバックオプションまたは類似のものがあります(ただし、2つの引数のみ)

于 2011-09-06T21:43:50.367 に答える
0

1 つのオプションは、Haskell のファンクターに類似した明示的なオプション タイプを使用することです。Maybe

残念ながら、既存の SQL 実装の多くは、ユーザー定義の代数データ型のサポートが不十分であり、これをきれいに行う必要があるユーザー定義型コンストラクターのサポートがさらに不十分です。

これは、明示的に要求した属性に対してのみ一種の「null」を回復しますが、null愚かな 3 値ロジックは必要ありません。Nothing == NothingであるTrue、ないunknown、またはnull

ユーザー定義の代数型のサポートは、情報が欠落している理由がいくつかある場合にも役立ちます。たとえば、次の Haskell 型と同等のデータベースは、明らかなアプリケーションの優れたソリューションになります。

data EmploymentStatus = Employed EmployerID | Unemployed | Unknown

(もちろん、これをサポートするデータベースは、通常よりも複雑な外部キー制約もサポートする必要があります。)

これを除けば、私はAPConedaywhenの 6NF に関する回答に同意します。

于 2013-05-30T22:39:16.967 に答える
0

1 つの代替手段として、次のエンティティ属性値モデルがあります。

 entity  attribute    value
 1       name         Banana Man
 1       birthdate    1968-06-20

生年月日が不明な場合は、その行を省略します。

于 2010-06-20T16:20:52.657 に答える
0

オプション 3: レコードライターの責任:

CREATE TABLE Person
(
  PersonId int PRIMARY KEY IDENTITY(1,1),
  Name nvarchar(100) NOT NULL,
  DateOfBirth datetime NOT NULL
)

目標が null 表現を排除することであるのに、なぜ null 表現を許可するようにモデルをゆがめるのでしょうか?

于 2010-06-22T19:57:45.523 に答える