sql >> Databasteknik >  >> RDS >> PostgreSQL

Få rader för de senaste 10 datumen

Det här ser inte misstänkt ut, men det är en jävla fråga .

Antaganden

crosstab() frågor

För att få högsta prestanda och korta frågesträngar (särskilt om du kör den här frågan ofta) föreslår jag tilläggsmodulen tablefunc tillhandahåller olika crosstab() funktioner. Grundläggande instruktioner:

Grundläggande frågor

Du måste få dessa rätt först.

De senaste 10 dagarna:

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

Siffror för de senaste 10 dagarna med fönsterfunktionen 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;

(Inklusive faktiska datum i denna fråga.)

Kolumnnamn för utdatakolumner (för fullständig lösning):

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;

Enkelt resultat med statiska kolumnnamn

Detta kan vara tillräckligt bra för dig - men vi ser inga faktiska datum i resultatet:

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

För upprepad användning föreslår jag att du skapar denna (mycket snabba) generiska C-funktion för 10 heltalskolumner en gång, för att förenkla saker och ting lite:

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

Detaljer i detta relaterade svar:

Då blir ditt samtal:

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!

Fullständig lösning med dynamiska kolumnnamn

Din faktiska fråga är mer komplicerad, du vill också ha dynamiska kolumnnamn.
För en given tabell kan den resulterande frågan se ut så här:

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");

Svårigheten är att destillera dynamiska kolumnnamn. Antingen sätter du frågesträngen för hand eller (mycket hellre) låt den här funktionen göra det åt dig:

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

Ring:

SELECT f_generate_date10_sql(1);

Detta genererar den önskade frågan , som du kör i tur och ordning.

db<>fiol här




  1. Primära nycklar i SQL Server

  2. Importerar gammal mysql-datamapp

  3. Varför kastar Hibernate org.hibernate.exception.LockAcquisitionException?

  4. Hur man tar bort lagrad procedur i MySQL