Oracle: 특정 범위에 걸쳐 "그룹화"하는 방법
다음과 같은 테이블이 있는 경우:
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);
기본적으로 히스토그램에 대한 데이터입니다.
X축에는 연령(또는 연령 범위)이 있고 Y축에는 카운트 n(또는 주파수)이 있습니다.
가장 간단한 형태에서는 이미 설명한 바와 같이 각 개별 연령 값의 수를 셀 수 있습니다.
SELECT age, count(*)
FROM tbl
GROUP BY age
그러나 x축에 대해 다른 값이 너무 많으면 그룹(또는 군집 또는 버킷)을 만들 수 있습니다.이 경우 10의 일정한 범위로 그룹화합니다.
a라고 은 피할 수 요.WHEN ... THEN
각 범위의 행 - 연령에 관한 것이 아니라면 수백 개가 될 수 있습니다.@NitinMidha @MathewFlaschen @MathewFlaschen @NitinMidha 。
이제 SQL을 구축해 보겠습니다.
먼저 다음과 같이 기간을 10개의 범위 그룹으로 분할해야 합니다.
- 0-9
- 10-19
- 20 - 29
- 기타.
이는 연령 열을 10으로 나눈 다음 결과의 FLOOR를 계산하여 달성할 수 있습니다.
FLOOR(age/10)
"FLOOR는 n 이하의 최대 정수를 반환합니다." http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions067.htm#SQLRF00643
그런 다음 원래 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
또한 하한 + 10 - 1 또는 각 범위의 상한 또는
FLOOR(age/10) * 10 + 10 - 1
마지막으로 양쪽을 다음과 같은 문자열로 연결합니다.
TO_CHAR(FLOOR(age/10) * 10) || '-' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1)
하면 것것 this this this this this this this this this this this가 생깁니다.'0-9', '10-19', '20-29'
syslog.
SQL은 다음과 같습니다.
SELECT
TO_CHAR(FLOOR(age/10) * 10) || ' - ' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1),
COUNT(*)
FROM tbl
GROUP BY FLOOR(age/10)
마지막으로 순서와 나이스 컬럼에일리어스를 적용합니다.
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를 참조하십시오.
@MathewFlaschen의 어프로치를 인정.상세만 설명했습니다.
다음은 서브쿼리에 "범위" 테이블을 작성한 후 이를 사용하여 메인 테이블에서 데이터를 분할하는 솔루션입니다.
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;
한 시간에 나타난 트랜잭션 수에 따라 데이터를 분류해야 했습니다.타임스탬프에서 시간을 추출하여 이 작업을 수행했습니다.
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
보시다시피 시간당 레코드 수를 쉽게 그룹화할 수 있습니다.
대신 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 컬럼을 추가하는 등 원하는 경우 이 아이디어를 개선할 수 있습니다.
이것이 도움이 되기를 바란다:)
Oracle 9i+를 사용하는 경우 다음과 같은 분석 기능을 사용할 수 있습니다.
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
나는 낮까지 샘플을 세어봐야 했다.@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
/
다음 솔루션을 사용해 볼 수 있습니까?
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
나의 접근법:
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 절과 group 절의 범위를 반복하지 않습니다.
- 하지만 어떤 사람은 나에게 어떻게 그것들을 매그니튜드별로 정렬하는지 알려주세요!
언급URL : https://stackoverflow.com/questions/2483140/oracle-how-to-group-by-over-a-range
'programing' 카테고리의 다른 글
angularjs ui-module - 앱 전체에서 글로벌한 마스터 상태를 구축하는 방법 (0) | 2023.03.14 |
---|---|
캔 각도외부 앱에 의해 영구 모델(서버 데이터베이스)이 변경된 경우 JS에서 보기를 자동으로 업데이트하시겠습니까? (0) | 2023.03.14 |
spring-web 용 스프링 부트 자동 설정을 방지하는 방법 (0) | 2023.03.14 |
AJAX를 사용하는 jQuery Select2 컨트롤에 동적으로 항목 추가 (0) | 2023.02.15 |
리액트 네이티브는 왜 자신을 정당화하지 않는가? (0) | 2023.02.15 |