PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Стабилен подход за създаване на SQL заявки програмно

По-добра заявка

Като за начало можете да поправите синтаксиса, да опростите и изясните доста:

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;
  • Надграждам върху моето актуализирано оформление на таблицата. Вижте цигулката по-долу.

  • Не се нуждаете от допълнителна подзаявка. Функциите на прозореца се изпълняват след агрегатни функции, така че можете да го вложите, както е показано.

  • Докато говорим за "ранг", вероятно искате да използвате rank() , а не row_number() .

  • Приемайки people.people_id е PK, можете да опростите GROUP BY .

  • Уверете се, че сте квалифицирали в таблица всички имена на колони, които може да са двусмислени

PL/pgSQL функция

След това бих написал plpgsql функция, която приема параметри за вашите променливи части. Внедряване на a - c от вашите точки. d е неясно, оставям това за вас да добавите.

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;

Обаждане:

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. Асоциативни обекти на БД и индексиране

  2. Как да групирате и свързвате масиви в PostgreSQL

  3. завъртане/кръстосване на данни от различни редове към колони с postgres

  4. Защо премахването на индекс отнема повече време от създаването му?

  5. Как да премахнете няколко таблици в PostgreSQL с помощта на заместващ знак