web-dev-qa-db-ja.com

nvarcharと数値フィールドでのNULLと空の文字列の処理に関する質問

これらと同様の質問がこの辺りに頻繁に現れることを理解しています。これらを投稿する前に検索しましたが、私の質問に完全に答えるQAスレッドは見つかりませんでした。テーブルでは、基本的にNULLs、空の文字列、および(純粋な)空白を「空白」として扱い、空白でないセルの数を数える必要があります。テーブルには、numericbitnvarchar列の組み合わせが含まれています。

Q1テーブル_TABLE1_には、次のデータ分布を持つ列COLUMN1 nvarchar(32)があります。

_Value    RowCount
N/A      80             -- string 'N/A'
NULL     20             -- actual nulls
_

次のクエリの最後が予期しない結果を返すのはなぜですか?

_SELECT SUM(CASE WHEN COLUMN1 IS NOT NULL THEN 1 ELSE 0 END)
FROM TABLE1             -- returns 80, as expected

SELECT SUM(CASE WHEN COLUMN1 NOT IN (NULL, '') THEN 1 ELSE 0 END)
FROM TABLE1             -- returns 80, as expected

SELECT SUM(CASE WHEN COLUMN1 NOT IN ('') THEN 1 ELSE 0 END)
FROM TABLE1             -- returns 80, but I expected 100.
_

Q2NULLsまたは空の文字列を含まない値で満たされた別の列COLUMN2 numeric(18, 0)があります(ただし、couldどちらか/両方を含む)。しかし、以下の2番目のクエリは、理解できない理由により失敗します。

_SELECT SUM(CASE WHEN COLUMN2 NOT IN ('', NULL) THEN 1 ELSE 0 END)
FROM TABLE1             -- returns full rowcount (100), as expected.

SELECT SUM(CASE WHEN COLUMN2 NOT IN (NULL, '') THEN 1 ELSE 0 END)
FROM TABLE1             --query FAILS! (Msg 8114, Level 16, State 5, Line 1. Error converting data type varchar to numeric.)
_

Q列のデータ型に関係なく、列のNULL、空の文字列、および純粋な空白をチェックするという私の要件に対するすべてを網羅した式とは何ですか?列名が(カーソル化された)変数_@column_からのものである場合、何で囲み、それと比較する必要がありますか? castからnvarcharを使用してLTRIM/RTRIMを使用してみましたが、率直に言って、この時点で少し迷っています。

私はSQL Server 2008を使用しています。これを読んでいただき、ご協力いただきありがとうございます。

3

Q1

_SELECT SUM(CASE WHEN COLUMN1 NOT IN ('') THEN 1 ELSE 0 END)
-- returns 80, but I expected 100.
_

なぜ100行が必要ですか?列がNULLである20行があります。式は次のように評価されます。

_SELECT SUM(CASE WHEN COLUMN1 <> '' THEN 1 ELSE 0 END)
_

NULLは不明を意味するため、等号または不等号の比較により、不明(この場合はfalse、またはより正確には、正確ではない)が得られます)。 column1がnullの場合、SQL Serverは、それが_'foo'_と等しいか、または_'foo'_と等しくないかを通知できません。

Q2

エラーは、暗黙的な変換と式の順序が原因です。最初のクエリでは、最初に文字列と比較し、次にNULLと比較しています。 NULLは文字列になります。これは後で参照されたため、基になる列(実行プランで確認できるはず)が暗黙的に文字列に変換されたためです。 2番目のクエリでは、最初にNULLと比較しているため、式のデータ型を判別するには、テーブルをチェックする必要があります。テーブルには数値が含まれているため、最初の引数はCONVERT(NUMERIC(18,2), NULL)と同じであり、空の文字列を数値に変換しようとします。これを試して、うまくいかない理由を確認してください。

_SELECT CONVERT(DECIMAL(10,2), '');
_

Q

すべてのデータ型で同じ式を使用するには、それらをすべて同じデータ型に変換できる必要があります。テーブルがあるとしましょう:

_CREATE TABLE #foo(a VARCHAR(30), b NUMERIC(18,2));

INSERT #foo SELECT '1', NULL;
INSERT #foo SELECT NULL, 4.5;
INSERT #foo SELECT '', 5.5;
_

次に、これらの4つの式の結果を比較します。

_SELECT a FROM #foo WHERE COALESCE(NULLIF(RTRIM(a), ''), '') <> '';
SELECT a FROM #foo WHERE COALESCE(NULLIF(RTRIM(a), ''), '') = '';

SELECT b FROM #foo WHERE COALESCE(NULLIF(RTRIM(b), ''), '') <> '';
SELECT b FROM #foo WHERE COALESCE(NULLIF(RTRIM(b), ''), '') = '';
_
4
Aaron Bertrand

SELECT SUM(COLUM1 NOT IN( '')THEN 1 ELSE 0 END)FROM TABLE1-80を返しますが、100を期待していました。

NULL値はSQLの空の文字列と同じではないので、取得した結果は正しく、SQL用語で意味があります。

NULLは「定義されていない値」と考えてください。したがって、定義された値である空の文字列(またはそのメーターのnull以外の値)とは異なります。英語の観点から見ると、nullは何も同じではありませんが、SQLでは同じではありません。

これで何が戻ると思いますか?

SELECT * FROM TABLE1 WHERE C1 NOT IN ('N/A')

上記のデータの場合、行は返されません。

SELECT SUM(CASE WHEN COLUMN2 NOT IN(NULL、 '')THEN 1 ELSE 0 END)FROM TABLE1 --query fails!

ここでは、数値を空の文字列と比較しようとしているため、クエリが失敗します。データ型は同じではありません。正しい結果を保証するには、互換性のあるデータ型の値を比較する必要があります。

Q3の意味がよくわからないので、お手伝いできません。

ヌルは注意が必要です。

1
NoChance