복붙노트

[SQL] 어떻게 하루에 1 개 이상의 레코드를 선택하려면?

SQL

어떻게 하루에 1 개 이상의 레코드를 선택하려면?

이것은 PostgreSQL의 문제입니다.

PostgreSQL 8.3.3 on i686-redhat-linux-gnu, compiled by GCC gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-9).

테이블 외모가 좋아 :

date_time           other_column
2012-11-01 00:00:00 ...
2012-11-02 01:00:00 ...
2012-11-02 02:00:00 ...
2012-11-02 03:00:00 ...
2012-11-02 04:00:00 ...
2012-11-03 05:00:00 ...
2012-11-03 06:00:00 ...
2012-11-05 00:00:00 ...
2012-11-07 00:00:00 ...
2012-11-07 00:00:00 ...
...

나는 특정 날짜 범위에서 하루에 최대 3 개 레코드를 선택합니다.

예를 들어, 나는 2012년 11월 2일에서 2012년 11월 5일 대부분의 3 개 기록을 선택합니다. 예상되는 결과는 다음과 같습니다

date_time           other_column
2012-11-02 01:00:00 ...
2012-11-02 02:00:00 ...
2012-11-02 03:00:00 ...
2012-11-03 05:00:00 ...
2012-11-03 06:00:00 ...
2012-11-05 00:00:00 ...

나는이에 몇 시간을 보냈습니다 아직도 그것을 알아낼 수 없습니다. 제발 도와주세요. :(

최신 정보: 단 하루에 하나 개의 레코드를 선택할 수 있습니다 시도 현재 SQL I :

SELECT DISTINCT ON (TO_DATE(SUBSTRING((date_time || '') FROM 1 FOR 10), 'YYYY-MM-DD')) *
FROM myTable
WHERE  date_time >=  '20121101 00:00:00'  
AND  date_time <= '20121130 23:59:59'

해결법

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

    1.

    SELECT date_time, other_column
    FROM  (
       SELECT *, row_number() OVER (PARTITION BY date_time::date) AS rn
       FROM   tbl
       WHERE  date_time >= '2012-11-01 0:0'
       AND    date_time <  '2012-12-01 0:0'
       ) x
    WHERE  rn < 4;
    

    최선의 해결책 : 바람직 현재 버전 9.2, 최신 버전으로 업그레이드합니다.

    기타 솔루션 :

    단지 몇 일 동안 당신은 UNION ALL을 사용 수 :

    SELECT date_time, other_column
    FROM   tbl t1
    WHERE  date_time >= '2012-11-01 0:0'
    AND    date_time <  '2012-11-02 0:0'
    LIMIT  3
    )
    UNION ALL 
    (
    SELECT date_time, other_column
    FROM   tbl t1
    WHERE  date_time >= '2012-11-02 0:0'
    AND    date_time <  '2012-11-03 0:0'
    LIMIT  3
    )
    ...
    

    괄호는 여기에 선택되지 않습니다.

    나는 같은 (자세한에 대한 링크를 포함하여) 여기에 게시 - 일 이상 generate_series와 해결 방법 ()가 있습니다.

    우리가 윈도우 기능을 가지기 전에 나는 옛날에 plpgsql 기능 다시 그것을 해결 한 수 있습니다

    CREATE OR REPLACE FUNCTION x.f_foo (date, date, integer
                             , OUT date_time timestamp, OUT other_column text)
      RETURNS SETOF record AS
    $BODY$
    DECLARE
        _last_day date;          -- remember last day
        _ct       integer := 1;  -- count
    BEGIN
    
    FOR date_time, other_column IN
       SELECT t.date_time, t.other_column
       FROM   tbl t
       WHERE  t.date_time >= $1::timestamp
       AND    t.date_time <  ($2 + 1)::timestamp
       ORDER  BY t.date_time::date
    LOOP
       IF date_time::date = _last_day THEN
          _ct := _ct + 1;
       ELSE
          _ct := 1;
       END IF;
    
       IF _ct <= $3 THEN
          RETURN NEXT;
       END IF;
    
       _last_day := date_time::date;
    END LOOP;
    
    END;
    $BODY$ LANGUAGE plpgsql STABLE STRICT;
    
    COMMENT ON FUNCTION f_foo(date3, date, integer) IS 'Return n rows per day
    $1 .. date_from (incl.)
    $2 .. date_to  (incl.)
    $3 .. maximim rows per day';
    

    요구:

    SELECT * FROM f_foo('2012-11-01', '2012-11-05', 3);
    
  2. ==============================

    2.다음은 모든 사용 date_trunc ( '일', DATE_TIME)하거나 날짜에 타임 스탬프를 절단하는 최신 캐스트에 응답합니다. 날짜 형식 문자열과 남이 할 필요가 없습니다. 설명서에 날짜 / 시간 함수를 참조하십시오.

    다음은 모든 사용 date_trunc ( '일', DATE_TIME)하거나 날짜에 타임 스탬프를 절단하는 최신 캐스트에 응답합니다. 날짜 형식 문자열과 남이 할 필요가 없습니다. 설명서에 날짜 / 시간 함수를 참조하십시오.

    이 SQLFiddle 방송 세 가지 응답 : http://sqlfiddle.com/#!12/0fd51/14 (DATE_TIME 그것에 중복을 가질 수 있다면, 반드시 동일한 결과하지만)는 입력 데이터에 대해 동일한 결과를 모두.

    문제를 해결하려면에 필터에 대한 IN-목록을 생성 한계와 상관 하위 쿼리를 사용할 수 있습니다 :

    SELECT a.date_time, a.other_column
    FROM table1 a
    WHERE a.date_time IN (
      SELECT b.date_time
      FROM table1 b
      WHERE b.date_time IS NOT NULL
        AND a.date_time::date = b.date_time::date
      ORDER BY b.date_time
      LIMIT 3
    )
    AND a.date_time::date BETWEEN '2012-11-02' AND '2012-11-05';
    

    이것은 대부분의 휴대용 접근해야한다 - 그것은 MySQL을하지 작업 (5.5 같은 적어도) MySQL은 IN 절에서 사용되는 하위 쿼리에 LIMIT를 지원하지 않기 때문에 비록. 그래도, sqlite3를과 PostgreSQL에서 작동, 및 대부분의 다른 데시벨에서 작동합니다.

    또 다른 옵션은, 당신이 원하는 날짜 범위를 선택 창 기능을 사용하여 행 번호 범위 내에서 행을 주석하는 것입니다, 다음 여분의 행을 제외 출력을 필터링 :

    SELECT date_time, other_column
    FROM (
      SELECT 
        date_time, 
        other_column, 
        rank() OVER (PARTITION BY date_trunc('day',date_time) ORDER BY date_time) AS n
      FROM Table1
      WHERE date_trunc('day',date_time) BETWEEN '2012-11-02' AND '2012-11-05'
      ORDER BY date_time
    ) numbered_rows
    WHERE n < 4;
    

    DATE_TIME이 고유하지 않으면 관계가 가능성, 즉 인 경우에, 결정 결과를 얻을, 또는 넥타이를 깨고 ROW_NUMBER에 의해 순서에 추가 조항을 추가하는 대신 ROW_NUMBER 중 하나 계급 또는 DENSE_RANK 창 기능을 사용하는 것이 좋습니다.

    당신이 순위를 사용하는 경우, 그것은 그들 모두를 적합 할 수없는 경우 행을 전혀 포함하지 것이다; 당신이 DENSE_RANK 사용하는 경우 그것은 그렇게 할 수있는 3 행 당 하루에 제한을 통해 이동하는 경우에도 모두 포함됩니다.

    다른 처리의 모든 종류의 윈도우 사양을 사용하여,이 방법도 가능합니다.

    여기에 완전히 PostgreSQL의 특정 있지만 재미 배열 집계 및 슬라이스를 사용하는 다른 제제는 아직입니다.

    SELECT b.date_time, b.other_column 
    FROM (
      SELECT array_agg(a.date_time ORDER BY a.date_time)
      FROM table1 a
      WHERE a.date_time::date BETWEEN '2012-11-02' 
        AND '2012-11-05'
      GROUP BY a.date_time::date
    ) x(arr) 
    INNER JOIN table1 b ON (b.date_time = ANY (arr[1:3]));
    
  3. ==============================

    3.나는 서브 - 선택 사용할 것이며, 왼쪽 외부 조인. 이 트릭을 수행해야합니다

    나는 서브 - 선택 사용할 것이며, 왼쪽 외부 조인. 이 트릭을 수행해야합니다

    select distinct(date_format(a.date_time,"%Y-%m-%d")) date_time, b.* from table a
    left outer join (
      select date_format(date_time,"%Y-%m-%d") dt, * from table limit 3
    ) b 
    on date_format(a.date_time,"%Y-%m-%d") = b.dt; 
    
  4. from https://stackoverflow.com/questions/13410315/how-to-select-more-than-1-record-per-day by cc-by-sa and MIT license