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

Pendekatan yang kuat untuk membuat kueri SQL secara terprogram

Kueri yang lebih baik

Sebagai permulaan, Anda dapat memperbaiki sintaks, menyederhanakan dan mengklarifikasi sedikit:

SELECT *
FROM  (
   SELECT p.person_id, p.name, p.team, sum(s.score)::int AS score
         ,rank() OVER (PARTITION BY p.team
                       ORDER BY sum(s.score) DESC)::int AS rnk
    FROM  person p
    JOIN  score  s USING (person_id)
    GROUP BY 1
   ) sub
WHERE  rnk < 3;
  • Membangun tata letak tabel saya yang diperbarui. Lihat biola di bawah.

  • Anda tidak memerlukan subquery tambahan. Fungsi jendela dijalankan setelah fungsi agregat, sehingga Anda dapat menyusunnya seperti yang ditunjukkan.

  • Saat berbicara tentang "peringkat", Anda mungkin ingin menggunakan rank() , bukan row_number() .

  • Dengan asumsi people.people_id adalah PK, Anda dapat menyederhanakan GROUP BY .

  • Pastikan untuk membuat tabel memenuhi syarat semua nama kolom yang mungkin ambigu

Fungsi PL/pgSQL

Kemudian saya akan menulis fungsi plpgsql yang mengambil parameter untuk bagian variabel Anda. Menerapkan a - c poin Anda. d tidak jelas, biarkan Anda menambahkannya.

CREATE OR REPLACE FUNCTION f_demo(_agg text       DEFAULT 'sum'
                               , _left_join bool  DEFAULT FALSE
                               , _where_name text DEFAULT NULL)
  RETURNS TABLE(person_id int, name text, team text, score int, rnk int) AS
$func$
DECLARE
   _agg_op  CONSTANT text[] := '{count, sum, avg}';  -- allowed functions
   _sql     text;
BEGIN

-- assert --
IF _agg ILIKE ANY (_agg_op) THEN
   -- all good
ELSE
   RAISE EXCEPTION '_agg must be one of %', _agg_op;
END IF;

-- query --
_sql := format('
SELECT *
FROM  (
   SELECT p.person_id, p.name, p.team, %1$s(s.score)::int AS score
         ,rank() OVER (PARTITION BY p.team
                       ORDER BY %1$s(s.score) DESC)::int AS rnk
    FROM  person p
    %2$s  score  s USING (person_id)
    %3$s
    GROUP BY 1
   ) sub
WHERE  rnk < 3
ORDER  BY team, rnk'
   , _agg
   , CASE WHEN _left_join THEN 'LEFT JOIN' ELSE 'JOIN' END
   , CASE WHEN _where_name <> '' THEN 'WHERE p.name LIKE $1' ELSE '' END
);

-- debug   -- quote when tested ok
-- RAISE NOTICE '%', _sql;

-- execute -- unquote when tested ok
RETURN QUERY EXECUTE _sql
USING  _where_name;   -- $1

END
$func$  LANGUAGE plpgsql;

Telepon:

SELECT * FROM f_demo();
SELECT * FROM f_demo('sum', TRUE, '%2');    
SELECT * FROM f_demo('avg', FALSE);
SELECT * FROM f_demo(_where_name := '%1_'); -- named param

SQL Fiddle




  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 format geometri Postgres ke WKT

  2. kapan harus memutuskan dan kapan harus mengakhiri pg client atau pool

  3. Gunakan kembali nilai pilih yang dihitung

  4. Menyimpan data.frame besar ke dalam PostgreSQL dengan R

  5. Mendapatkan kunci yang dibuat secara otomatis dari penyisipan baris di musim semi 3 / PostgreSQL 8.4.9