web-dev-qa-db-ja.com

null値を一意の値としてカウントする

次のような列のさまざまな値をカウントする必要があります。

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など)
  • 場合
18
David
select  count(distinct col1) + count(distinct case when col1 is null then 1 end)
from    YourTable
23
Andomar

時間が数値の場合、整数のみの場合:

select count(distinct coalesce(hour, 0.1)) cnt from test;

それ以外の場合は、浮動小数点の場合は、NULLを文字列に変更します。

例えば

select count(distinct coalesce(to_char(hour), 'a')) cnt from test;
17
user1788325
select 
   count(0) 
from
  (
      select distinct hour from hours
  )

SqlFiddle

8
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 ;
2
ypercubeᵀᴹ

多分

    select count(distinct hour||' ') from hours;

しましょう?

2
Andres
select count(distinct nvl(hour,0)) from hours;
2
Giampaolo

NVL()COALESCE()またはCASEを使用するだけでより効率的なクエリを取得できることがほぼ確実であることを考えると、要件はかなり奇妙だと思います。しかし、サブクエリのみを使用して、適切な結果を得ることができました(およびNULL値の有無に対処しました)。 FROM句でサブクエリを使用せずにこれを実行する方法はまだありません。

SQLフィドル

クエリ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つ...いずれか:

  1. 使用する TO_CHARはNULL以外の値をデータ型VARCHAR2に変換し、NVLNULL値をVARCHAR2に変換します'NULL'または
  2. 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 |
1
Ben

Andresの回答は、COUNT以外の関数をまったく使用せずに、要件を完全に満たしている回答です。

select count(distinct hour||' ') from hours;

私は別の目的で同じものを探していました(何でも使用できました)が、これを見るまでは正しくも効率的でもなかったようです。Andresに感謝します。このような単純なソリューションでありながら強力なソリューションです。

1
arana

私が指定した基準に適合させることができる最も近いものはこれです:( 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の基準に適合します。

0
Ben

おそらく最も簡単な方法は、DUMPを使用することです。

SELECT COUNT(DISTINCT DUMP(hour)) AS distinct_count
FROM hours;

出力:3

DBFiddle Demo

0
Lukasz Szozda