Объединить несколько полей в строке запроса в plpgsql - PullRequest
1 голос
/ 17 марта 2012

Я использую plpgsql и hibernate и хочу создать функцию, которая содержит строку запроса, приведенную ниже.В предложении select я хочу объединить 3 поля, но во время выполнения этого запроса я получаю сообщение об ошибке, подобное:

ОШИБКА: синтаксическая ошибка в или около "''"
Состояние SQL: 42601
Контекст: PL / pgSQL функция "est_fn_dept_wise_emp_report" строка 30 при открытии

Я недавно использую хранимые функции, это может быть основной вопрос, но каким-то образом мне не удалось найти решение.

 query1 = 'SELECT  est_emp_empmaster.emp_no AS est_emp_empmaster_emp_no,
            adm_m_department.dept_name AS adm_m_department_dept_name,
            adm_m_subdepartment.sub_dept_id AS adm_m_subdepartment_sub_dept_id,
            adm_m_subdepartment.sub_dept_name AS adm_m_subdepartment_sub_dept_name,
            est_m_designation.desig_name AS est_m_designation_desig_name,
            est_emp_empmaster.first_name'|| ' ' ||'est_emp_empmaster.middle_name'|| ' '               ||'est_emp_empmaster.surname AS empname
    FROM public.adm_m_department adm_m_department
        INNER JOIN public.adm_m_subdepartment adm_m_subdepartment
        ON adm_m_department.dept_id = adm_m_subdepartment.dept_id
        INNER JOIN public.est_emp_empmaster est_emp_empmaster
        ON adm_m_department.dept_id = est_emp_empmaster.dept_id
        AND adm_m_subdepartment.sub_dept_id = est_emp_empmaster.sub_dept_id
        INNER JOIN public.est_emp_salary est_emp_salary
        ON est_emp_empmaster.emp_no = est_emp_salary.emp_no
        INNER JOIN public.est_m_designation est_m_designation
        ON est_emp_salary.pre_desig_code = est_m_designation.desig_code
        AND est_emp_salary.retired_flag ='|| quote_literal('N') ||'
         WHERE   est_emp_empmaster.corp_coun_id=0 or est_emp_empmaster.corp_coun_id is null or est_emp_empmaster.corp_coun_id = '|| quote_literal($1) ||'
         ORDER BY adm_m_department.dept_id,adm_m_subdepartment.sub_dept_id,est_emp_empmaster.emp_no ASC';


    OPEN refcur FOR
         EXECUTE query1;
    LOOP
         FETCH refcur INTO return_record;
         EXIT WHEN NOT FOUND;
         RETURN NEXT return_record;
    END LOOP;
    CLOSE refcur;**

Приведенный выше запрос выполняется нормально, если я выполняю его без выполнения через строку запроса.Но так как я хочу использовать этот запрос для нескольких условий и в этих условиях, я хочу изменить этот запрос, чтобы получить разные результаты.

Ответы [ 2 ]

2 голосов
/ 13 февраля 2013

Это может быть намного проще, безопаснее и быстрее (при условии, по крайней мере, Postgres 8.4):

 CREATE OR REPLACE FUNCTION foo(_corp_coun_id int) -- guessing type
  RETURNS TABLE (
    emp_no        int  -- guessing data types ..
   ,dept_name     text -- .. replace with actual types
   ,sub_dept_id   int
   ,sub_dept_name text
   ,desig_name    text
   ,empname       text) AS
$func$
BEGIN

RETURN QUERY
SELECT em.emp_no
      ,dp.dept_name
      ,sb.sub_dept_id
      ,sb.sub_dept_name
      ,ds.desig_name
      ,concat_ws(' ', em.first_name, em.middle_name, em.surname) --  AS empname
FROM   adm_m_department    dp
JOIN   adm_m_subdepartment su ON sb.dept_id = dp.dept_id
JOIN   est_emp_empmaster   em ON em.dept_id = sb.dept_id 
                             AND em.sub_dept_id = sb.sub_dept_id
JOIN   est_emp_salary      sl ON sl.emp_no = em.emp_no
                             AND sl.retired_flag = 'N'    -- untangled join cond.
JOIN   est_m_designation   ds ON ds.desig_code = sl.pre_desig_code
WHERE  em.corp_coun_id = 0 OR
       em.corp_coun_id IS NULL OR
       em.corp_coun_id = $1
ORDER  BY dp.dept_id, sb.sub_dept_id, em.emp_no;

END    
$func$
  LANGUAGE plpgsql SET search_path=public;
  • Чтобы ответить на ваш основной вопрос : используйте concat_ws() для простой и безопасной конкатенации нескольких столбцов (не сбой при NULL).

  • Здесь вам не нужен динамический SQL, поскольку переменные являются только значениями (не идентификаторами).

  • Вам не нужно CURSOR здесь.

  • Вам не нужно LOOP.RETURN QUERY делает то же самое, проще и быстрее.

  • Вам не нужны псевдонимы столбцов, только имена параметров OUT (неявно имена столбцов в RETURNS TABLE (...))релевантный.

  • Замените квалификацию множественной схемы public. в вашем запросе одним SET search_path = public.

  • Я также распутал ваш запрос,использовали псевдонимы коротких таблиц и переформатировали, чтобы было легче читать.

  • Вам даже не нужен plpgsql здесь.Может быть проще функция SQL :

 CREATE OR REPLACE FUNCTION foo(_corp_coun_id int)
  RETURNS TABLE (
    emp_no        int  -- guessing data types ..
   ,dept_name     text -- .. replace with actual types!
   ,sub_dept_id   int
   ,sub_dept_name text
   ,desig_name    text
   ,empname       text) AS
$func$
SELECT em.emp_no
      ,dp.dept_name
      ,sb.sub_dept_id
      ,sb.sub_dept_name
      ,ds.desig_name
      ,concat_ws(' ', em.first_name, em.middle_name, em.surname) --  AS empname
FROM   adm_m_department    dp
JOIN   adm_m_subdepartment sb ON sb.dept_id = dp.dept_id
JOIN   est_emp_empmaster   em ON em.dept_id = sb.dept_id 
                             AND em.sub_dept_id = sb.sub_dept_id
JOIN   est_emp_salary      sl ON sl.emp_no = em.emp_no
                             AND sl.retired_flag = 'N'    -- untangled join cond.
JOIN   est_m_designation   ds ON ds.desig_code = sl.pre_desig_code
WHERE  em.corp_coun_id = 0 OR
       em.corp_coun_id IS NULL OR
       em.corp_coun_id = $1
ORDER  BY dp.dept_id, sb.sub_dept_id, em.emp_no;
$func$
  LANGUAGE sql SET search_path=public;
1 голос
/ 19 марта 2012

Я нашел решение вышеупомянутой проблемы, на самом деле оно хорошо работало в обычном запросе, но у меня возникла проблема при запуске его в динамическом запросе.Решение вышеуказанной проблемы заключается в следующем. Еще раз спасибо ..:)

est_emp_empmaster.first_name||'' ''||est_emp_empmaster.middle_name||'' ''||est_emp_empmaster.surname AS empname
...