복붙노트

[SQL] 오라클 : 어떻게 이상의 범위 "에 의해 그룹"에?

SQL

오라클 : 어떻게 이상의 범위 "에 의해 그룹"에?

이 같은 테이블이있는 경우 :

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 별에 관심이있을 것입니다.

해결법

  1. ==============================

    1.

    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
    
  2. ==============================

    2.시험:

    시험:

    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);
    
  3. ==============================

    3.당신이 찾고있는 것은 기본적으로 히스토그램 데이터입니다.

    당신이 찾고있는 것은 기본적으로 히스토그램 데이터입니다.

    당신은 y 축에 나이 (연령 범위) x 축에 카운트 N (또는 주파수)를 가질 것이다.

    이미 설명한 것처럼 간단한 형태로, 하나는 단순히 각각 별개의 세 값의 수를 셀 수 :

    SELECT age, count(*)
    FROM tbl
    GROUP BY age
    

    그러나, X 축에 대해 너무 많은 다른 값이 존재하는 경우, 하나의 그룹 (또는 클러스터 또는 버킷)를 생성 할 수있다. 10의 일정한 범위에 의해 귀하의 경우에, 당신은 그룹.

    우리는 각각의 범위에 대한 WHEN ... THEN 라인을 작성 피할 수 있습니다 - 그것은 나이 아니었다면 수백있을 수 있습니다. 대신, @MatthewFlaschen에 의한 접근 방식은 @NitinMidha 언급 이유로 바람직하다.

    이제 SQL을 만들어 보자 ...

    첫째, 우리는 그렇게 같은 10의 범위-그룹으로 세를 분할해야합니다

    이것은 10 세 열을 분할하고, 그 결과의 FLOOR를 계산함으로써 달성 될 수있다 :

    FLOOR(age/10)
    

    "FLOOR는 N보다 작거나 같은 정수 가장 큰 반환" http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions067.htm#SQLRF00643

    그 후 우리는 원래의 SQL을 가지고 그 표현과 나이를 대체 :

    SELECT FLOOR(age/10), count(*)
    FROM tbl
    GROUP BY FLOOR(age/10)
    

    이것은 OK이지만, 우리는 아직 범위를 볼 수 없습니다. 그 대신 우리는 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)
    

    이 만듭니다 '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)
    

    마지막으로, 주문 및 좋은 열 별칭을 적용

    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의 일정한 덩어리로 분류하지만, 동적 클러스터링을 필요로하지 않을 수 있습니다. 오라클이 포함 된 고급 히스토그램 기능을 가지고, http://docs.oracle.com/cd/E16655_01/server.121/e15858/tgsql_histo.htm#TGSQL366 참조

    그의 접근에 대한 @MatthewFlaschen에 크레딧; 난 단지 세부 사항을 설명했다.

  4. ==============================

    4.여기서 서브 쿼리에 "범위"테이블을 생성하고 기본 테이블의 데이터를 분할하기 위해 사용하는 용액이다 :

    여기서 서브 쿼리에 "범위"테이블을 생성하고 기본 테이블의 데이터를 분할하기 위해 사용하는 용액이다 :

    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;
    
  5. ==============================

    5.한 시간에 등장 얼마나 많은 트랜잭션 데이터를 그룹화했다. 나는 타임 스탬프에서 시간을 추출하여 이런 짓을 :

    한 시간에 등장 얼마나 많은 트랜잭션 데이터를 그룹화했다. 나는 타임 스탬프에서 시간을 추출하여 이런 짓을 :

    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
    

    당신이 볼 수 있듯이,이 시간 당 레코드 수를 그룹화하는 좋은 쉬운 방법을 제공합니다.

  6. ==============================

    6.대신하여 테이블과 그룹에 AGE_RANGE 테이블과 age_range_id 필드를 추가합니다.

    대신하여 테이블과 그룹에 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의 열을 추가 - - 만약 당신이 좋아하면 당신은이 아이디어를 구체화 할 수 있습니다하지만 난 당신을 떠날 것이다.

    도움이 되었기를 바랍니다 :)

  7. ==============================

    7.오라클 9i에 +를 사용하는 경우, 당신은 NTILE 분석 기능을 사용할 수 있습니다 :

    오라클 9i에 +를 사용하는 경우, 당신은 NTILE 분석 기능을 사용할 수 있습니다 :

    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)는 네 개의 버킷 / 파티션 각각 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
    
  8. ==============================

    8.나는 하루 샘플의 수를 얻을 수 있었다. @Clarkey I에 의해 영감은 ISO-8601 날짜 형식으로 타임 스탬프의 샘플의 날짜를 추출하는 TO_CHAR를 사용하여 GROUP BY의 것을 사용하고 ORDER BY 절. (또한 영감, 나 또한 다른 사람에게 유용 경우 여기를 게시 할 수 있습니다.)

    나는 하루 샘플의 수를 얻을 수 있었다. @Clarkey I에 의해 영감은 ISO-8601 날짜 형식으로 타임 스탬프의 샘플의 날짜를 추출하는 TO_CHAR를 사용하여 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
    /
    
  9. ==============================

    9.당신은 솔루션 아래 시도 할 수 있습니다 :

    당신은 솔루션 아래 시도 할 수 있습니다 :

    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 
    
  10. ==============================

    10.나의 접근 방식 :

    나의 접근 방식 :

    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  
    
  11. from https://stackoverflow.com/questions/2483140/oracle-how-to-group-by-over-a-range by cc-by-sa and MIT license