Quantcast
Channel: Planet MySQL
Viewing all articles
Browse latest Browse all 1081

DISTINCT, COUNT, そしてNULL

$
0
0
本エントリはFirebird Advent Calendar 2017の14日目です。

DISTINCT, COUNT, そしてNULL

唐突ですが、次の文章のうち間違っているものは? SELECT文で。。。。

(1) 行数を数えるときにはCOUNT(*)
(2) 行数を数えるときにはCOUNT(カラム名)でも(1)と同じ
(3) カラムのユニークな行数を数えるときはCOUNT(DISTINCT カラム名)
(4) 複数カラムのユニークな行数を数えるときはCOUNT(DISTINCT カラム名1, カラム名2)

じゃ確認してみましょう。

create table t1(i1 int, i2 int);
insert into t1 values(1,1);
insert into t1 values(1,2);
insert into t1 values(2,3);
select count(*) from t1;

COUNT
=====================
3

select count(i1) from t1;

COUNT
=====================
3

(1),(2)ともによさそうに見えますね。。。。ってちょっと待ったー! もう一行nullを含む行を追加してみましょう。

insert into t1 values(null,3);

select count(*) from t1;

COUNT
=====================
4

select count(i1) from t1;

COUNT
=====================
3

そう、実は集約関数はNULLを除外します。ただし「COUNT(*)」は例外的にNULLを除外しないのです。
そのため、上記のような違いが現れます。Firebirdに限らず、標準SQLに準拠しているものはすべてそうなります。

SQLのCOUNT(*)とCOUNT(列名)では結果が異なる(山本隆の開発日誌)

select count(distinct i1) from t1;

COUNT
=====================
2

これはまず、distinctで1,2,nullの三行になり、count(列名)はnullを除外するので、2となります。
これはcountを除いた以下のクエリで一目両全です。(3)はOKそうですね。

select distinct i1 from t1;

I1
============
&ltnull&gt
1
2

次に(4)にトライしてみると。。。。エラーですね。

select count(distinct i1,i2) from t1;
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 1, column 25
-,

そう、Firebirdを含めたほとんどのRDBMSではCOUNT(DISTINCT マルチカラム)は許されていないのです。
そのため、よく代案として利用されるのが、DISTINCTをサブクエリにした以下のクエリや、DISTINCTの代わりにGROUP BYを使うものです。

select count(*) from (select distinct i1,i2 from t1);

COUNT
=====================
4

もう一つはカラムを、そのカラムに出てこないデリミタを入れてCONCATするものです。

select count(distinct i1 || '-' || i2) from t1;

COUNT
=====================
3

OK, って一行減ってますね。。。。これもcountを除くと意味がわかります。

select distinct i1 || '-' || i2 from t1;

CONCATENATION
=======================
&ltnull&gt
1-1
1-2
2-2

NULLをCONCATするとNULLになり、それはCOUNTに計上されません。そのため巷のDISTINCTをサブクエリに
する方法は、データにNULLがあると正しくないのです。厳密にいうと、こうなります。

select count(*) from (select distinct i1,i2 from t1 where i1 is not null and i2 is not null);

COUNT
=====================
3

本ブログエントリの最初のほうで「ほとんどのRDBMSではCOUNT(DISTINCT マルチカラム)は許されていない」
と記述しましたが、唯一許されているのがMySQLです。

create table t1(i1 int, i2 int);
insert into t1 values(1,1);
insert into t1 values(1,2);
insert into t1 values(2,3);
insert into t1 values(null,3);

select count(distinct i1,i2) from t1;
+-----------------------+
| count(distinct i1,i2) |
+-----------------------+
| 3 |
+-----------------------+
1 row in set (0.03 sec)

ということで、正しくでるのですが、DISTINCTしたマルチカラムそれぞれにIS NOT NULLをANDでつけていないクエリで
NULLを含むデータを投入して「結果が違う〜」という向きがいるので、それはこのような違いがある、ということを
覚えておいてください!

結果(1),(3)はOK, (2)は違う(カラムがnot nullならOK), (4) はMySQLだけ、ということになります。

JUGEMテーマ:コンピュータ




Viewing all articles
Browse latest Browse all 1081

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>