PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Pobierz wiersze z ostatnich 10 dat

Nie wygląda to podejrzanie, ale to piekielne pytanie .

Założenia

crosstab() zapytania

Aby uzyskać najwyższą wydajność i krótkie ciągi zapytań (zwłaszcza jeśli często uruchamiasz to zapytanie) sugeruję dodatkowy moduł tablefunc udostępnianie różnych crosstab() Funkcje. Podstawowe instrukcje:

Podstawowe zapytania

Najpierw musisz to zrobić dobrze.

Ostatnie 10 dni:

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

Liczby z ostatnich 10 dni przy użyciu funkcji okna 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;

(Nie obejmuje rzeczywistych dat w tym zapytaniu).

Nazwy kolumn dla kolumn wyjściowych (dla pełnego rozwiązania):

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;

Prosty wynik ze statycznymi nazwami kolumn

To może być dla Ciebie wystarczające, ale w wyniku nie widzimy rzeczywistych dat:

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

Do wielokrotnego użytku sugeruję utworzenie tej (bardzo szybkiej) ogólnej funkcji C dla 10 kolumn liczb całkowitych raz, aby trochę uprościć:

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

Szczegóły w tej powiązanej odpowiedzi:

Wtedy Twoja rozmowa stanie się:

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!

Pełne rozwiązanie z dynamicznymi nazwami kolumn

Twoje rzeczywiste pytanie jest bardziej skomplikowane, potrzebujesz także dynamicznych nazw kolumn.
Dla danej tabeli wynikowe zapytanie może wyglądać tak:

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

Trudność polega na wydestylowaniu dynamicznych nazw kolumn. Albo złóż łańcuch zapytania ręcznie, albo (raczej) pozwól tej funkcji zrobić to za Ciebie:

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

Zadzwoń:

SELECT f_generate_date10_sql(1);

To generuje żądane zapytanie , które wykonujesz po kolei.

db<>fiddle tutaj




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nieudane logowanie z istniejącym użytkownikiem w PostgreSQL

  2. Uzyskaj tylko najnowsze dane z ostatniego tygodnia i zsumuj jakąś kolumnę

  3. Jak zwrócić identyfikatory na wkładkach z Ibatis ( ze słowem kluczowym RETURNING )

  4. Nie można połączyć się z Postgres DB, ponieważ typ uwierzytelniania 10 nie jest obsługiwany

  5. Rekord aktywny:Zapytanie JSON