次のような列のさまざまな値をカウントする必要があります。
Hours
1
1
2
null
null
null
結果はでなければなりません。私のクエリは:
select count(distinct hour) from hours;
しかしそれは返します:2.私もテストしました:
select count(*) from hours group by hour
しかし、3つの行を返します。
(1) 3
(2) 2
(3) 1
Null値を1つの値としてカウントし、distinctを使用して繰り返し値のカウントを回避するにはどうすればよいですか?
私は高度なSQLを学習しています。彼らは私にすべてのソリューションに対するこれらの要件を求めています:
クエリを解決するために必要なサブクエリの数を最小限に抑えるようにしてください。さらに、次の構文を使用することはできません。
- FROMまたはSELECTでSELECT。サブクエリを許可されています(WHEREまたはHAVINGでSELECT)
- COUNT(COUNT。.))、SUM(COUNT。.))などの集計関数の組み合わせ。
- あなたがそれを避けることができればUNION。
- 非標準機能(NVLなど)
- 場合
select count(distinct col1) + count(distinct case when col1 is null then 1 end)
from YourTable
時間が数値の場合、整数のみの場合:
select count(distinct coalesce(hour, 0.1)) cnt from test;
それ以外の場合は、浮動小数点の場合は、NULLを文字列に変更します。
例えば
select count(distinct coalesce(to_char(hour), 'a')) cnt from test;
select
count(0)
from
(
select distinct hour from hours
)
SELECT
( SELECT COUNT(DISTINCT hour)
FROM hours
)
+ CASE WHEN EXISTS
( SELECT *
FROM hours
WHERE hour IS NULL
)
THEN 1
ELSE 0
END
AS result
FROM dual ;
多分
select count(distinct hour||' ') from hours;
しましょう?
select count(distinct nvl(hour,0)) from hours;
NVL()
、COALESCE()
またはCASE
を使用するだけでより効率的なクエリを取得できることがほぼ確実であることを考えると、要件はかなり奇妙だと思います。しかし、サブクエリのみを使用して、適切な結果を得ることができました(およびNULL
値の有無に対処しました)。 FROM
句でサブクエリを使用せずにこれを実行する方法はまだありません。
クエリ1:
SELECT nnh.not_null_hours + nh.null_hours
FROM (
SELECT COUNT(DISTINCT t.hour) not_null_hours
FROM example_table t
) nnh
CROSS JOIN (
SELECT 1 null_hours
FROM dual
WHERE EXISTS (
SELECT 1
FROM example_table t
WHERE t.hour IS NULL
)
UNION ALL
SELECT 0 null_hours
FROM dual
WHERE NOT EXISTS (
SELECT 1
FROM example_table t
WHERE t.hour IS NULL
)
) nh
結果:
| NNH.NOT_NULL_HOURS+NH.NULL_HOURS |
------------------------------------
| 3 |
これは、要件に対処するために多くの努力をすることになります。より単純なオプションはNVL
を使用することであり、次に2つの単純な選択肢のうちの1つ...いずれか:
TO_CHAR
はNULL以外の値をデータ型VARCHAR2に変換し、NVL
はNULL
値をVARCHAR2に変換します'NULL'
またはNVL
を、結果セットに存在しないことがわかっているマジック番号(つまり、テーブルの制約のため)とともに使用します。クエリ1:
SELECT
COUNT(DISTINCT NVL(TO_CHAR(hour), 'NULL')) using_to_char_null
, COUNT(DISTINCT NVL(hour, -1)) using_magic_number
FROM example_table
結果:
| USING_TO_CHAR_NULL | USING_MAGIC_NUMBER |
-------------------------------------------
| 3 | 3 |
Andresの回答は、COUNT
以外の関数をまったく使用せずに、要件を完全に満たしている回答です。
select count(distinct hour||' ') from hours;
私は別の目的で同じものを探していました(何でも使用できました)が、これを見るまでは正しくも効率的でもなかったようです。Andresに感謝します。このような単純なソリューションでありながら強力なソリューションです。
私が指定した基準に適合させることができる最も近いものはこれです:( SQL Fiddle )
クエリ1:
SELECT COUNT(*)
FROM example_table t1
WHERE t1.ROWID IN (
SELECT MAX(t2.ROWID)
FROM example_table t2
GROUP BY t2.hour
)
結果:
| COUNT(*) |
------------
| 3 |
他の制限を考慮して、ROWID
疑似列が許可されているかどうかはわかりませんが、NULL
値を正常に処理します。私はROWIDがOracleの外部に存在するとは思わないので、これはおそらく質問の精神に反することになりますが、少なくともlistedの基準に適合します。
おそらく最も簡単な方法は、DUMP
を使用することです。
SELECT COUNT(DISTINCT DUMP(hour)) AS distinct_count
FROM hours;
出力:3