【问题标题】:More than one row returned by a subquery used as an expression but only in function子查询返回的多行用作表达式但仅在函数中
【发布时间】:2020-11-14 05:03:46
【问题描述】:

当我使用一个函数时,它给出了提到的错误,但是当单独使用相同的代码时它工作得很好。问题出在哪里?

使用函数:https://dbfiddle.uk/?rdbms=postgres_12&fiddle=c4b0c8a59d2bd851284ed624ab1c335d

使用干净选择填充:https://dbfiddle.uk/?rdbms=postgres_12&fiddle=7ccca6c70061aff1f6c394815aa8e9b1

样本数据:

create table report
(report_day date,
 tickets_no integer,
 tickets_stake numeric,
 promo_tickets_no integer,
 promo_tickets_stake numeric,
 group_id integer);
 
 insert into report
 values
 ('2020-07-20',12,569.6, 2, 44,1),
 ('2020-07-20',61,2000, 5, 260,2),
  ('2020-07-21',35,1244.2, 11, 250,1),
  ('2020-07-21',100,2500.5, 29, 575,2),
   ('2020-07-22',66,2511.8, 23, 670,1),
   ('2020-07-22',125,3358.2, 50, 990,2);

CREATE OR REPLACE FUNCTION report(arguments json)
  RETURNS json AS
$BODY$
     
DECLARE 
        
    dateFrom date;
    dateTo date;
        selectedType integer;
BEGIN 
        
    dateFrom := cast(arguments->>'dateFrom' as date);
    dateTo := cast(arguments->>'dateTo' as date);
    selectedType := cast(arguments->>'selectedType' as integer);

RETURN (
    WITH full_data as (
 with tickets as (
  select 
    report_day
  , sum(tickets_no) as tickets_no
  , sum(tickets_stake) as tickets_stake
  FROM report
  WHERE selectedType = 0
  AND report_day between dateFrom and dateTo
  GROUP BY 1)
  
, promo_tickets as (
  select 
    report_day
  , sum(promo_tickets_no) as promo_tickets_no
  , sum(promo_tickets_stake) as promo_tickets_stake
  FROM report
  WHERE selectedType = 1
  AND report_day between dateFrom and dateTo
  GROUP BY 1)
  
  select 
    t.report_day 
  , sum(coalesce(t.tickets_no,0) + coalesce(pt.promo_tickets_no,0)) as tickets_no                             
  , sum(coalesce(t.tickets_stake,0) + coalesce(pt.promo_tickets_stake,0)) as tickets_no
  FROM tickets t
  LEFT JOIN promo_tickets pt on t.report_day = pt.report_day                                    
   GROUP BY 1
   ORDER BY 1)
        
select row_to_json(full_data) from full_data
);

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
  
  select * from report(json_build_object('dateFrom', '2020-07-20', 'dateTo', '2020-07-22','selectedType', 0 ))

【问题讨论】:

    标签: sql postgresql stored-functions


    【解决方案1】:

    因为您试图从一个应该只返回一行的函数返回多行。向您的函数添加一个参数,最好是主键列(我想是tickets_no),例如

    CREATE OR REPLACE FUNCTION report(arguments json, i_tickets_no int)
    

    并将查询重写为

    WITH full_data AS
     (WITH tickets AS
         (SELECT report_day,
                SUM(tickets_no) AS tickets_no,
                SUM(tickets_stake) AS tickets_stake
           FROM report
          WHERE selectedType = 0
            AND report_day BETWEEN dateFrom AND dateTo
            AND tickets_no = i_tickets_no
          GROUP BY 1),
        promo_tickets as
         (select report_day,
                SUM(promo_tickets_no) as promo_tickets_no,
                SUM(promo_tickets_stake) as promo_tickets_stake
           FROM report
          WHERE selectedType = 1
            AND report_day BETWEEN dateFrom AND dateTo
          GROUP BY 1)
        
        select t.report_day,
               SUM(COALESCE(t.tickets_no, 0) + COALESCE(pt.promo_tickets_no, 0)) AS tickets_no,
               SUM(COALESCE(t.tickets_stake, 0) +
                   COALESCE(pt.promo_tickets_stake, 0)) AS tickets_no
          FROM tickets t
          LEFT JOIN promo_tickets pt
            ON t.report_day = pt.report_day
         GROUP BY 1
         ORDER BY 1)
    

    并通过添加第二个参数来调用。

    Demo

    【讨论】:

      【解决方案2】:

      如果您希望函数像查询一样返回报表对象数组,请更改此部分:

      select row_to_json(full_data) from full_data
      

      将行聚合成一个数组:

      select json_agg(row_to_json(full_data)) from full_data
      

      如果希望函数返回多行,则需要进行两处更改:

      CREATE OR REPLACE FUNCTION report(arguments json)
        RETURNS table (row_to_json json) AS
      

      对于return

      RETURN QUERY (
          WITH full_data as (
      

      更新fiddle here.

      【讨论】:

      • 不可以返回多个json行吗?
      • @sh4rkyy 如果您的函数返回类型是json,则不是。请查看我的答案的更新。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      • 2018-02-13
      • 1970-01-01
      • 2021-07-13
      相关资源
      最近更新 更多