【问题标题】:Concatenate multiple fields in query string in plpgsql连接plpgsql中查询字符串中的多个字段
【发布时间】:2012-04-02 14:37:23
【问题描述】:

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

如果我在不通过查询字符串执行的情况下执行上述查询,则运行良好。但由于我想将此查询用于多个条件,并且在这些条件下我想修改此查询以获得不同的结果。

【问题讨论】:

    标签: sql postgresql stored-procedures plpgsql


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我找到了解决上述问题的方法, 实际上它在正常查询中运行良好,但在动态查询中运行它时遇到问题。 上述问题的解决方法如下。再次感谢..:)

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

      【讨论】:

      • 我怀疑每个人都有一个中间名——在这种情况下,解决方案就不好了。
      • 实际上,在我的情况下,我只是想连接我已经拥有的查询字符串。我仍然会接受您的回答,因为它可能对其他开发人员有所帮助。感谢分享知识。
      猜你喜欢
      • 2017-01-30
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-18
      • 2023-03-09
      相关资源
      最近更新 更多