1. ホーム
  2. sql

[解決済み】COUNT(*) vs. COUNT(1) vs. COUNT(pk): どちらが良いですか?[重複]。

2022-04-01 13:39:48

質問

この3つのバリエーションはよく見かけますね。

SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;

私が見る限り、どれも同じことをするものであり、私のコードベースではこの3つを使用しています。しかし、私は同じことを別の方法で行うのは好きではありません。どれにこだわればいいのでしょうか?どれが他の2つよりも優れているのでしょうか?

どのように解決するのですか?

ボトムライン

どちらかを使用する COUNT(field) または COUNT(*) そして、もしあなたのデータベースが COUNT(tableHere) または COUNT(tableHere.*) を使用します。

要するに COUNT(1) を使用することができます。これは一芸に秀でたもので、望んだことを実現することはほとんどありませんし、そのような稀なケースでは count(*)

使用方法 count(*) カウントする場合

使用方法 * を使用すると、結合の場合でも、すべてをカウントする必要があるすべてのクエリで *

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

ただし COUNT(*) LEFT結合では、下位テーブルが親テーブルにマッチしない場合でも1を返します。

SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

というアドバイスに惑わされないでください。 * は、テーブルから行全体を取得します。 * が遅い。 その *SELECT COUNT(*)SELECT * は互いに関係なく、全く別のものであり、ただ共通のトークン、すなわち * .

代替構文

実際、テーブル名と同じフィールド名を付けることが許されない場合、RDBMSの言語設計者は、フィールドに COUNT(tableNameHere) と同じセマンティクスです。 COUNT(*) . 例

行を数えるには、次のようにします。

SELECT COUNT(emp) FROM emp

そして、もっとシンプルにすることもできるはずです。

SELECT COUNT() FROM emp

そして、LEFT JOINについては、このようにすることができます。

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

しかし、それができないのです( COUNT(tableNameHere) 標準SQLでは、フィールドにテーブル名と同じ名前を付けることが許されているからです。

CREATE TABLE fruit -- ORM-friendly name
(
fruit_id int NOT NULL,
fruit varchar(50), /* same name as table name, 
                and let's say, someone forgot to put NOT NULL */
shape varchar(50) NOT NULL,
color varchar(50) NOT NULL
)

nullを使ったカウント

また、フィールドの名前がテーブル名と一致する場合、そのフィールドをNULL可能にするのは良い方法とは言えません。例えば、'Banana'、'Apple'、NULL、'Pears' という値が fruit フィールドを使用します。この場合、すべての行をカウントすることはできず、4行ではなく、3行しかカウントされません。

SELECT count(fruit) FROM fruit

RDBMS の中にはそのような原理(テーブルの行数を数えるために、COUNT のパラメータとしてテーブル名を受け付ける)を持つものもありますが、これは Postgresql で動作します(もし subordinate フィールド名とテーブル名の間に名前の衝突がない限り、です。)

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

しかし、これは後で混乱を招く可能性があります。 subordinate というのは、テーブルの行ではなく、フィールド (これは null 可能です) をカウントするからです。

だから、安全のために、使ってください。

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

count(1) : 一芸に秀でたポニー

特に COUNT(1) である。 一発芸 1つのテーブルクエリにのみ有効です。

SELECT COUNT(1) FROM tbl

しかし、結合を使う場合、そのトリックはマルチテーブルクエリではそのセマンティクスが混乱することなく機能せず、特に書くことはできません。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

では、ここでのCOUNT(1)はどういう意味なのでしょうか?

SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

これかな......?

-- counting all the subordinates only
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

それともこれ......?

-- or is that COUNT(1) will also count 1 for boss regardless if boss has a subordinate
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

注意深く考えることで、次のように推論することができます。 COUNT(1) と同じです。 COUNT(*) 結合のタイプに関係なく。 しかし、LEFT JOINの結果に対しては COUNT(1) として動作するようにします。 COUNT(subordinate.boss_id) , COUNT(subordinate.*)

だから、次のどちらかを使えばいいのです。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Postgresqlで動作する場合、セットの基数をカウントしたいことは明らかです。

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

集合の基数を数えるもうひとつの方法は、とても英語的です(ただ、テーブル名と同じ名前のカラムは作らないでください)。 http://www.sqlfiddle.com/#!1/98515/7

select boss.boss_name, count(subordinate)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

することはできません。 http://www.sqlfiddle.com/#!1/98515/8

select boss.boss_name, count(subordinate.1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

このようにすることもできますが、これは間違った結果をもたらします。 http://www.sqlfiddle.com/#!1/98515/9

select boss.boss_name, count(1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name