在plpgsql中连接查询字符串中的多个字段

时间:2012-03-17 05:54:03

标签: sql postgresql stored-procedures plpgsql

我正在使用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;**

如果我执行它而不执行查询字符串,上面的查询运行正常。但是因为我想在多个条件下使用此查询,并且在这些情况下我想修改此查询以获得不同的结果。

1 个答案:

答案 0 :(得分:2)

这可以更多更简单,更安全,更快(至少假设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

  • 您不需要LOOPRETURN 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;