programing

Oracle: 특정 범위에 걸쳐 "그룹화"하는 방법

procenter 2023. 3. 14. 23:32
반응형

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

반응형