PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana cara memilih lebih dari 1 catatan per hari?

Saya ingin memilih paling banyak 3 catatan per hari dari rentang tanggal tertentu.

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;

Poin utama

  • Gunakan fungsi jendela row_number() . rank() atau dense_rank() akan salah menurut pertanyaan - lebih dari 3 catatan mungkin dipilih dengan duplikat stempel waktu.

  • Karena Anda tidak mendefinisikan yang mana baris yang Anda inginkan per hari, jawaban yang benar adalah tidak menyertakan ORDER BY klausa dalam fungsi jendela. Memberi Anda pilihan sewenang-wenang, yang cocok dengan pertanyaan.

  • Saya mengubah WHERE . Anda klausa dari

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

    untuk

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

    Sintaks Anda akan gagal untuk kasus sudut seperti '20121130 23:59:59.123' .

    Apa yang disarankan @Craig:

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

    .. akan bekerja dengan benar, tetapi merupakan anti-pola terkait kinerja. Jika Anda menerapkan pemeran atau fungsi ke kolom database Anda dalam ekspresi, indeks biasa tidak dapat digunakan.

Solusi untuk PostgreSQL 8.3

Solusi terbaik :Tingkatkan ke versi yang lebih baru, sebaiknya ke versi saat ini 9.2.

Solusi lain :

Hanya untuk beberapa hari Anda dapat menggunakan 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
)
...

Tanda kurung tidak opsional di sini.

Untuk hari lagi ada solusi dengan generate_series() - sesuatu seperti yang saya posting di sini (termasuk tautan ke lainnya).

Saya mungkin telah menyelesaikannya dengan fungsi plpgsql kembali di masa lalu sebelum kami memiliki fungsi jendela:

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

Telepon:

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. Postgres INTERVAL menggunakan nilai dari tabel

  2. Manakah GUI PostgreSQL Terbaik? Perbandingan 2021

  3. daftar postgresql dan pesan tabel berdasarkan ukuran

  4. Apa format untuk string / URL koneksi PostgreSQL?

  5. Soket domain PostgreSQL UNIX vs soket TCP