このようなテーブルがある場合:
pkey age
---- ---
1 8
2 5
3 12
4 12
5 22
「グループ化」して、各年齢のカウントを取得できます。
select age,count(*) n from tbl group by age;
age n
--- -
5 1
8 1
12 2
22 1
年齢範囲でグループ化するには、どのクエリを使用できますか?
age n
----- -
1-10 2
11-20 2
20+ 1
私は10gR2を使用していますが、11g固有のアプローチにも興味があります。
SELECT CASE
WHEN age <= 10 THEN '1-10'
WHEN age <= 20 THEN '11-20'
ELSE '21+'
END AS age,
COUNT(*) AS n
FROM age
GROUP BY CASE
WHEN age <= 10 THEN '1-10'
WHEN age <= 20 THEN '11-20'
ELSE '21+'
END
試してください:
select to_char(floor(age/10) * 10) || '-'
|| to_char(ceil(age/10) * 10 - 1)) as age,
count(*) as n from tbl group by floor(age/10);
探しているのは、基本的に histogram のデータです。
X軸に年齢(または年齢範囲)があり、y軸にカウントn(または頻度)があります。
最も簡単な形式では、すでに説明したように、各個別の年齢値の数を単純にカウントできます。
SELECT age, count(*)
FROM tbl
GROUP BY age
ただし、x軸の値が多すぎる場合は、グループ(またはクラスターやバケット)を作成する必要があります。あなたの場合、10の一定範囲でグループ化します。
各範囲にWHEN ... THEN
行を書くことを避けることができます-年齢に関するものではない場合は数百になります。代わりに、@ NitinMidhaが述べている理由から、@ MatthewFlaschenによるアプローチが望ましいです。
では、SQLをビルドしましょう...
まず、次のように年齢を10の範囲グループに分割する必要があります。
これは、年齢列を10で除算し、結果のFLOORを計算することで実現できます。
FLOOR(age/10)
"FLOORはn以下の最大整数を返します" http://docs.Oracle.com/cd/E11882_01/server.112/e26088/functions067.htm#SQLRF0064
次に、元のSQLを使用して、ageをその式に置き換えます。
SELECT FLOOR(age/10), count(*)
FROM tbl
GROUP BY FLOOR(age/10)
これは問題ありませんが、範囲はまだ見えません。代わりに、0, 1, 2 ... n
である計算されたフロア値のみが表示されます。
実際の下限を取得するには、再度10を掛けて0, 10, 20 ... n
を取得する必要があります。
FLOOR(age/10) * 10
下限bound + 10-1または
FLOOR(age/10) * 10 + 10 - 1
最後に、両方を次のような文字列に連結します。
TO_CHAR(FLOOR(age/10) * 10) || '-' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1)
これにより、'0-9', '10-19', '20-29'
などが作成されます。
これで、SQLは次のようになります。
SELECT
TO_CHAR(FLOOR(age/10) * 10) || ' - ' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1),
COUNT(*)
FROM tbl
GROUP BY FLOOR(age/10)
最後に、順序とNice列のエイリアスを適用します。
SELECT
TO_CHAR(FLOOR(age/10) * 10) || ' - ' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1) AS range,
COUNT(*) AS frequency
FROM tbl
GROUP BY FLOOR(age/10)
ORDER BY FLOOR(age/10)
ただし、より複雑なシナリオでは、これらの範囲はサイズ10の一定のチャンクにグループ化されない場合がありますが、動的なクラスタリングが必要です。 Oracleには、より高度なヒストグラム関数が含まれています。 http://docs.Oracle.com/cd/E16655_01/server.121/e15858/tgsql_histo.htm#TGSQL366 を参照してください。
彼のアプローチに対する@MatthewFlaschenの功績。詳細のみを説明しました。
サブクエリで「範囲」テーブルを作成し、これを使用してメインテーブルからデータをパーティション分割するソリューションを次に示します。
SELECT DISTINCT descr
, COUNT(*) OVER (PARTITION BY descr) n
FROM age_table INNER JOIN (
select '1-10' descr, 1 rng_start, 10 rng_stop from dual
union (
select '11-20', 11, 20 from dual
) union (
select '20+', 21, null from dual
)) ON age BETWEEN nvl(rng_start, age) AND nvl(rng_stop, age)
ORDER BY descr;
1時間に表示されるトランザクション数でデータをグループ化する必要がありました。タイムスタンプから時間を抽出することでこれを行いました:
select extract(hour from transaction_time) as hour
,count(*)
from table
where transaction_date='01-jan-2000'
group by
extract(hour from transaction_time)
order by
extract(hour from transaction_time) asc
;
出力を与える:
HOUR COUNT(*)
---- --------
1 9199
2 9167
3 9997
4 7218
ご覧のとおり、これにより、1時間あたりのレコード数を簡単にグループ化できます。
age_rangeテーブルとage_range_idフィールドをテーブルに追加し、代わりにそれでグループ化します。
// DDLを言い訳しますが、アイデアを得る必要があります
create table age_range(
age_range_id tinyint unsigned not null primary key,
name varchar(255) not null);
insert into age_range values
(1, '18-24'),(2, '25-34'),(3, '35-44'),(4, '45-54'),(5, '55-64');
//もう一度DMLを言い訳しますが、アイデアを得る必要があります
select
count(*) as counter, p.age_range_id, ar.name
from
person p
inner join age_range ar on p.age_range_id = ar.age_range_id
group by
p.age_range_id, ar.name order by counter desc;
必要に応じて、このアイデアを改良できます-age_rangeテーブルにfrom_age to_ageカラムを追加します-しかし、それはあなたにお任せします。
お役に立てれば :)
日ごとにサンプル数を取得する必要がありました。 @Clarkeyに触発され、TO_CHARを使用してタイムスタンプからISO-8601日付形式にサンプルの日付を抽出し、GROUP BY句とORDER BY句で使用しました。 (さらにインスピレーションを得て、他の人に役立つようにここに投稿します。)
SELECT
TO_CHAR(X.TS_TIMESTAMP, 'YYYY-MM-DD') AS TS_DAY,
COUNT(*)
FROM
TABLE X
GROUP BY
TO_CHAR(X.TS_TIMESTAMP, 'YYYY-MM-DD')
ORDER BY
TO_CHAR(X.TS_TIMESTAMP, 'YYYY-MM-DD') ASC
/
Oracle 9i +を使用している場合、mightNTILE
分析関数 を使用できます。
_WITH tiles AS (
SELECT t.age,
NTILE(3) OVER (ORDER BY t.age) AS tile
FROM TABLE t)
SELECT MIN(t.age) AS min_age,
MAX(t.age) AS max_age,
COUNT(t.tile) As n
FROM tiles t
GROUP BY t.tile
_
NTILEの注意点は、パーティションの数のみを指定でき、ブレークポイント自体は指定できないことです。したがって、適切な数値を指定する必要があります。 IE:100行の場合、NTILE(4)
は4つのバケット/パーティションのそれぞれに25行を割り当てます。分析関数をネストすることはできないため、サブクエリ/サブクエリファクタリングを使用してそれらを階層化し、必要な粒度を取得する必要があります。それ以外の場合は、次を使用します。
_ SELECT CASE t.age
WHEN BETWEEN 1 AND 10 THEN '1-10'
WHEN BETWEEN 11 AND 20 THEN '11-20'
ELSE '21+'
END AS age,
COUNT(*) AS n
FROM TABLE t
GROUP BY CASE t.age
WHEN BETWEEN 1 AND 10 THEN '1-10'
WHEN BETWEEN 11 AND 20 THEN '11-20'
ELSE '21+'
END
_
私のアプローチ:
select range, count(1) from (
select case
when age < 5 then '0-4'
when age < 10 then '5-9'
when age < 15 then '10-14'
when age < 20 then '15-20'
when age < 30 then '21-30'
when age < 40 then '31-40'
when age < 50 then '41-50'
else '51+'
end
as range from
(select round(extract(day from feedback_update_time - feedback_time), 1) as age
from txn_history
) ) group by range
以下の解決策を試すことができます:
SELECT count (1), '1-10' where age between 1 and 10
union all
SELECT count (1), '11-20' where age between 11 and 20
union all
select count (1), '21+' where age >20
from age