PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm thế nào để chọn nhiều hơn 1 bản ghi mỗi ngày?

Tôi muốn chọn nhiều nhất 3 bản ghi mỗi ngày từ một phạm vi ngày cụ thể.

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;

Những điểm chính

  • Sử dụng hàm cửa sổ row_number() . rank() hoặc dense_rank() sẽ sai theo câu hỏi - hơn 3 bản ghi có thể được chọn với các bản sao dấu thời gian.

  • Vì bạn không xác định cái nào hàng bạn muốn mỗi ngày, câu trả lời đúng là không bao gồm ORDER BY mệnh đề trong hàm cửa sổ. Cung cấp cho bạn lựa chọn tùy ý, phù hợp với câu hỏi.

  • Tôi đã thay đổi WHERE của bạn mệnh đề từ

    WHERE  date_time >= '20121101 00:00:00'  
    AND    date_time <= '20121130 23:59:59'
    

    đến

    WHERE  date_time >=  '2012-11-01 0:0'  
    AND    date_time <   '2012-12-01 0:0'
    

    Cú pháp của bạn sẽ không thành công đối với các trường hợp góc như '20121130 23:59:59.123' .

    Những gì @Craig đề xuất:

    date_time::date BETWEEN '2012-11-02' AND '2012-11-05'
    

    .. sẽ hoạt động chính xác, nhưng là một mô hình chống lại hiệu suất. Nếu bạn áp dụng một lớp hoặc một hàm cho cột cơ sở dữ liệu của mình trong biểu thức, thì không thể sử dụng các chỉ mục thuần túy.

Giải pháp cho PostgreSQL 8.3

Giải pháp tốt nhất :Nâng cấp lên phiên bản mới hơn, tốt nhất là phiên bản 9.2 hiện tại.

Các giải pháp khác :

Chỉ trong vài ngày bạn có thể sử dụng 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
)
...

Dấu ngoặc đơn không phải là tùy chọn ở đây.

Trong ngày nữa có các giải pháp thay thế với generate_series() - một cái gì đó giống như tôi đã đăng ở đây (bao gồm một liên kết đến nhiều hơn).

Tôi có thể đã giải quyết nó bằng hàm plpgsql ngày xưa trước khi chúng ta có các hàm cửa sổ:

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';

Gọi:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách POSITION () hoạt động trong PostgreSQL

  2. Dữ liệu mùa xuân JPA + Bỏ qua Hibernate Các hàng đã khóa (PostgreSQL)

  3. Hiệu suất OLTP kể từ PostgreSQL 8.3

  4. Tóm lại, lập chỉ mục cơ sở dữ liệu với B + tree và Hash để so sánh

  5. Mối quan hệ không tồn tại