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

Dapatkan baris untuk 10 tanggal terakhir

Ini terlihat tidak mencurigakan, tapi ini pertanyaan yang sangat buruk .

Asumsi

crosstab() kueri

Untuk mendapatkan kinerja terbaik dan string kueri pendek (terutama jika Anda sering menjalankan kueri ini) saya sarankan modul tambahan tablefunc menyediakan berbagai crosstab() fungsi. Petunjuk dasar:

Kueri dasar

Anda harus melakukannya dengan benar terlebih dahulu.

10 hari terakhir:

SELECT DISTINCT date
FROM   book
WHERE  sid = 1
ORDER  BY date DESC
LIMIT  10;

Angka selama 10 hari terakhir menggunakan fungsi jendela dense_rank() :

SELECT *
FROM  (
   SELECT name
        , dense_rank() OVER (ORDER BY date DESC) AS date_rnk
        , count
   FROM   book
   WHERE  sid = 1
   ) sub
WHERE  date_rnk < 11
ORDER  BY name, date_rnk DESC;

(Tidak termasuk tanggal aktual dalam kueri ini.)

Nama kolom untuk kolom keluaran (untuk solusi lengkap):

SELECT 'bookname, "' || string_agg(to_char(date, 'DD/MM/YYYY'), '", "' ORDER BY date) || '"'
FROM  (
   SELECT DISTINCT date
   FROM   book
   WHERE  sid = 1
   ORDER  BY date DESC
   LIMIT  10
   ) sub;

Hasil sederhana dengan nama kolom statis

Ini mungkin cukup baik untuk Anda - tetapi kami tidak melihat tanggal sebenarnya dalam hasil:

SELECT * FROM crosstab(
  'SELECT *
   FROM  (
      SELECT name
           , dense_rank() OVER (ORDER BY date DESC) AS date_rnk
           , count
      FROM   book
      WHERE  sid = 1
      ) sub
   WHERE  date_rnk < 11
   ORDER  BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
 ) AS (bookname text
     , date1 int, date2 int, date3 int, date4 int, date5 int
     , date6 int, date7 int, date8 int, date9 int, date10 int);

Untuk penggunaan berulang, saya sarankan Anda membuat fungsi C generik (sangat cepat) ini untuk 10 kolom bilangan bulat sekali, untuk sedikit menyederhanakan:

CREATE OR REPLACE FUNCTION crosstab_int10(text, text)
  RETURNS TABLE (bookname text
               , date1 int, date2 int, date3 int, date4 int, date5 int
               , date6 int, date7 int, date8 int, date9 int, date10 int)
  LANGUAGE C STABLE STRICT AS
'$libdir/tablefunc','crosstab_hash';

Detail dalam jawaban terkait ini:

Kemudian panggilan Anda menjadi:

SELECT * FROM crosstab(
  'SELECT *
   FROM  (
      SELECT name
           , dense_rank() OVER (ORDER BY date DESC) AS date_rnk
           , count
      FROM   book
      WHERE  sid = 1
      ) sub
   WHERE  date_rnk < 11
   ORDER  BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
 );  -- no column definition list required!

Solusi lengkap dengan nama kolom dinamis

Pertanyaan Anda yang sebenarnya lebih rumit, Anda juga menginginkan nama kolom yang dinamis.
Untuk tabel tertentu, kueri yang dihasilkan dapat terlihat seperti ini:

SELECT * FROM crosstab_int10(
  'SELECT *
   FROM  (
      SELECT name
           , dense_rank() OVER (ORDER BY date DESC) AS date_rnk
           , count
      FROM   book
      WHERE  sid = 1
      ) sub
   WHERE  date_rnk < 11
   ORDER  BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
   ) AS t(bookname
        , "04/11/2015", "05/11/2015", "06/11/2015", "07/11/2015", "08/11/2015"
        , "09/11/2015", "10/11/2015", "11/11/2015", "15/11/2015", "17/11/2015");

Kesulitannya adalah menyaring nama kolom dinamis. Baik merakit string kueri dengan tangan, atau (lebih tepatnya) biarkan fungsi ini melakukannya untuk Anda:

CREATE OR REPLACE FUNCTION f_generate_date10_sql(_sid int = 1) 
  RETURNS text
  LANGUAGE sql AS
$func$
SELECT format(
 $$SELECT * FROM crosstab_int10(
  'SELECT *
   FROM  (
      SELECT name
           , dense_rank() OVER (ORDER BY date DESC) AS date_rnk
           , count
      FROM   book
      WHERE  sid = %1$s
      ) sub
   WHERE  date_rnk < 11
   ORDER  BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
   ) AS ct(bookname, "$$
|| string_agg(to_char(date, 'DD/MM/YYYY'), '", "' ORDER BY date) || '")'
 , _sid)
FROM  (
   SELECT DISTINCT date
   FROM   book
   WHERE  sid = 1
   ORDER  BY date DESC
   LIMIT  10
   ) sub
$func$;

Telepon:

SELECT f_generate_date10_sql(1);

Ini menghasilkan kueri yang diinginkan , yang Anda jalankan secara bergantian.

db<>fiddle di sini




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Konversi Bermain! evolusi kerangka kerja dari MySQL ke PostgreSQL

  2. Migrasikan Akses MS ke PostgreSQL

  3. bagaimana cara menangani kata sandi yang selalu berubah di sqlalchemy+psycopg2?

  4. Streaming data dari Postgres ke Python

  5. Menggunakan JSONB di PostgreSQL:Cara Efektif Menyimpan &Mengindeks Data JSON di PostgreSQL