动态查询的结果可以输入 CTE 吗?

Can results of a dynamic query feed into a CTE?

成功生成基于输入参数的动态查询。现在,我希望将此动态查询的结果输入到 Common Table Expression (CTE) 中。如果不将其分成两个功能,这可能吗?我在 CTE 顶部的 EXECUTE qry... 行出现错误。

CREATE OR REPLACE FUNCTION spaidb.filter_opportunities(
    owner_id integer,
    team_id integer,
    member_id integer,
    forecast json,
    opportunity_type json,
    stage character varying,
    close_date_start timestamp without time zone,
    close_date_end timestamp without time zone,
    created_since timestamp without time zone,
    updated_since timestamp without time zone,
    unchanged_since timestamp without time zone,
    sorting json,
    current_page integer DEFAULT 1,
    page_size integer DEFAULT 100)
    RETURNS json
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
  DECLARE
    qry text := 'SELECT * from spaidb.v_opportunities';
    where_clause text := '';
    sort_clause text := '';
  BEGIN
    where_clause := where_clause || spaidb.add_clause(owner_id, '"ownerId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(team_id, '"teamId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(member_id, '"memberId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(stage, 'stage =  AND ');
    where_clause := where_clause || spaidb.add_clause(created_since, 'created >=  AND ');
    where_clause := where_clause || spaidb.add_clause(updated_since, '"lastUpdated" >=  AND ');
    where_clause := where_clause || spaidb.add_clause(unchanged_since, '"lastUpdated" <=  AND ');
    where_clause := where_clause || spaidb.add_clause(close_date_start, '"closeDate" >=  AND ');
    where_clause := where_clause || spaidb.add_clause(close_date_end, '"closeDate" <=  AND ');
    where_clause := where_clause || spaidb.unpack_json_where('"opportunityType"', opportunity_type);
    where_clause := where_clause || spaidb.unpack_json_where('forecast', forecast);

    IF where_clause != '' THEN
      where_clause := ' WHERE ' || LEFT(where_clause, -5); -- add WHERE, strip last ' AND '
    END IF;

    sort_clause := spaidb.unpack_json_sort(sorting);

    qry := query || where_clause || sort_clause || ';';
    RAISE NOTICE '%', qry; -- looks good

  WITH opportunities_found AS (
    EXECUTE qry USING owner_id, team_id, member_id, stage, created_since, updated_since, unchanged_since, close_date_start, close_date_end;
  )
  SELECT json_build_object(
      'totalItems',(SELECT COUNT(*) FROM opportunities_found),
      'currentPage', current_page,
      'pageSize', page_size,
      'results', COALESCE((SELECT json_agg(l.*) FROM (SELECT opportunities_found.* FROM opportunities_found LIMIT page_size OFFSET ((current_page - 1) * page_size)) l ), '[]')
    );
*/
  END;
$BODY$;

构建的查询如下所示(取决于哪些输入参数为空)...

SELECT * from spaidb.v_opportunities WHERE "closeDate" >=  AND "closeDate" <=  AND ("forecast" = 'Forecast' OR "forecast" = 'Upside') ORDER BY "ownerName" asc, "amount" desc;

非json输入仅在非NULL时才直接用于WHERE子句。 json 输入是值数组,用于搜索特定字段或要按其方向排序的列列表。这就是很难在 CTE 的 WITH 中使用视图的原因。

不得不将其分解为单独的函数 - 一个是 SQL,另一个是 PLPGSQL:

CREATE OR REPLACE FUNCTION spaidb.filter_opportunities(
    owner_id integer,
    team_id integer,
    member_id integer,
    forecast_input json,
    opportunity_type json,
    stage character varying,
    close_date_start timestamp without time zone,
    close_date_end timestamp without time zone,
    created_since timestamp without time zone,
    updated_since timestamp without time zone,
    unchanged_since timestamp without time zone,
    sorting json)
    RETURNS TABLE("accountName" character varying, "opportunityId" integer, "opportunityName" character varying, "ownerId" integer, "ownerName" character varying, "opportunityType" character varying, amount integer, "atRisk" boolean, discovery integer, value integer, spotlight integer, forecast character varying, "closeDate" timestamp without time zone, "stageId" integer, "stageName" character varying, "actionableInsights" json) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
    ROWS 1000

AS $BODY$
  DECLARE
    qry varchar := 'SELECT * from spaidb.v_opportunities';
    where_clause varchar := '';
    sort_clause varchar := '';
  BEGIN
    where_clause := where_clause || spaidb.add_clause(owner_id, '"ownerId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(team_id, '"teamId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(member_id, '"memberId" =  AND ');
    where_clause := where_clause || spaidb.add_clause(stage, 'stage =  AND ');
    where_clause := where_clause || spaidb.add_clause(created_since, 'created >=  AND ');
    where_clause := where_clause || spaidb.add_clause(updated_since, '"lastUpdated" >=  AND ');
    where_clause := where_clause || spaidb.add_clause(unchanged_since, '"lastUpdated" <=  AND ');
    where_clause := where_clause || spaidb.add_clause(close_date_start, '"closeDate" >=  AND ');
    where_clause := where_clause || spaidb.add_clause(close_date_end, '"closeDate" <=  AND ');
    where_clause := where_clause || spaidb.unpack_json_where('"opportunityType"', opportunity_type);
    where_clause := where_clause || spaidb.unpack_json_where('forecast', forecast_input);

    IF where_clause != '' THEN
      where_clause := ' WHERE ' || LEFT(where_clause, -5); -- add WHERE, strip last ' AND '
    END IF;

    sort_clause := spaidb.unpack_json_sort(sorting);

    qry := qry || where_clause || sort_clause || ';';
    RAISE NOTICE '%', qry;
    RETURN QUERY EXECUTE qry USING owner_id, team_id, member_id, stage, created_since, updated_since, unchanged_since, close_date_start, close_date_end;
  END;
$BODY$;

CREATE OR REPLACE FUNCTION spaidb.filter_opportunities_paginated(
    owner_id integer,
    team_id integer,
    member_id integer,
    forecast_input json,
    opportunity_type json,
    stage character varying,
    close_date_start timestamp without time zone,
    close_date_end timestamp without time zone,
    created_since timestamp without time zone,
    updated_since timestamp without time zone,
    unchanged_since timestamp without time zone,
    sorting json,
    current_page integer DEFAULT 1,
    page_size integer DEFAULT 100)
    RETURNS json
    LANGUAGE 'sql'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
    WITH opportunities_found AS (
    
      SELECT * from spaidb.filter_opportunities(
        owner_id,
        team_id,
        member_id,
        forecast_input,
        opportunity_type,
        stage,
        close_date_start,
        close_date_end,
        created_since,
        updated_since,
        unchanged_since,
        sorting
     )

    )
    SELECT json_build_object(
      'totalItems',(SELECT COUNT(*) FROM opportunities_found),
      'currentPage', current_page,
      'pageSize', page_size,
      'results', COALESCE((SELECT json_agg(o.*) FROM (SELECT opportunities_found.* FROM opportunities_found LIMIT page_size OFFSET ((current_page - 1) * page_size)) o ), '[]')
    );
$BODY$;