如何在 POSTGRESQL 中编写普通的选择过程

Vik*_*ram 1 postgresql

我无法在 PostgreSQL 中编写正常的选择过程。我在 SQL Server 方面有很好的经验。但 Postgres 看起来完全是一个不同的星球。

有人能帮我如何在 Postgres 中写这个语句吗?

create proc procedurename @somedate date
 begin
select * from sometable where date>= @somedate
end
Run Code Online (Sandbox Code Playgroud)

我可以像这样执行它

exec procedurename 2017-05-02
Run Code Online (Sandbox Code Playgroud)

我尝试编写一个存储过程,它返回一个带有类似内容的表

    Create or replace function hrms.salary() returns table(
lastmodified    timestamp without time zone ,
employeeid  integer ,
insuranceno character varying   ,
uanno   character varying   ,
basic   integer ,
hra numeric ,
conveyence  integer ,
fixedallowance  integer ,
epf numeric ,
eps numeric ,
esic    numeric ,
bankname    character varying   ,
ifsccode    character varying   ,
bankaccount character varying   ,
totalsalary integer 
) as
 $Body$
Begin
with pivotchart as(
SELECT * FROM hrms.crosstab(
  $$ SELECT employeeid,today,count(employeeid) as countid 
  FROM hrms.timesheet 
  where dated>='2017-09-01'
  and dated< '2017-09-01'::timestamp+ '1 MONTH'::INTERVAL
  group by employeeid,today $$,
  $$ select distinct today 
  from hrms.timesheet $$
)as
finalresult(employeeid int,leave int,present int,absent int, holiday int)
),
groupedresults as(
select employeeid ,
sum(present) as present,
sum(absent) as absent,
sum(holiday) as holiday,
sum(leave) as leave
from pivotchart
group by employeeid
),
numberofdays as(
SELECT  extract(day from DATE_TRUNC('month', now()::timestamptz) + '1 MONTH'::INTERVAL
      - DATE_TRUNC('month', now()::timestamptz))::int as interval
),
joinsofvalue as(
select emp.firstname,
emp.lastname,
emp.fathername,
grp.employeeid,
grp.Present,
grp.HOLIDAY,
grp.ABSENT,
grp.LEAVE,
sal.basic as Totalbasic,
(sal.basic)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedbasic,
sal.hra as totalHRA,
(sal.hra)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedHRA,
sal.conveyence as totalconveyence,
(sal.conveyence)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedconveyence,
sal.fixedallowance as totalfixedallowance,
(sal.fixedallowance)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedFA,
sal.epf as totalemployeeprovidendfund,
(sal.epf)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedEPF,
sal.eps as totalemployeepensionscheme,
(sal.eps)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedEPS,
sal.esic as totalemployeestateinsurance,
(sal.esic)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as calculatedESIC,
sal.totalsalary as GrossSalary,
(sal.totalsalary)/(select interval from numberofdays )* ((select interval from numberofdays)-(absent))as NETSalary
from (groupedresults as grp
right outer join 
hrms.employee as emp
on 
grp.employeeid = emp.employeeid)
left outer join
hrms.salarystructure as sal
on emp.employeeid=sal.employeeid
)
select * from joinsofvalue;
end;
$Body$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)

它创建了一个没有任何问题的函数。

Query returned successfully with no result in 38 msec.
Run Code Online (Sandbox Code Playgroud)

但当我再次尝试查询它时。使用

select * from hrms.salary()
Run Code Online (Sandbox Code Playgroud)

它给了我一个错误说明

ERROR:  column reference "employeeid" is ambiguous
LINE 14: select employeeid ,
                ^
DETAIL:  It could refer to either a PL/pgSQL variable or a table column.
Run Code Online (Sandbox Code Playgroud)

没有文档可以解决这个问题,但我确信 with 语句之后的所有内容都可以正常工作。事实上,我已经创建了一个具有相同查询的视图并且它有效。但我需要包含一个参数,这就是我需要它的原因。

小智 5

Postgres 没有过程。您需要一个返回结果的函数:

create function some_function(p_somedate date)
  returns setof sometable
as
$$
select * 
from sometable 
where date >= p_somedate;
$$
language sql;
Run Code Online (Sandbox Code Playgroud)

然后运行:

select *
from some_function(date '2017-11-01');
Run Code Online (Sandbox Code Playgroud)

另请参阅此处和此处手册中的示例

显示真实代码后编辑:

您使用的language plpgsql函数与普通 SQL 函数不同(language sql如我的示例中所示)。

如手册中所述,如果 PL/pgSQL 函数想要返回结果,则需要使用返回查询。

一个普通的 SQL 函数可以简单地编写一条 SELECT 语句。


如果你想坚持使用 PL/pgSQL,你需要这样的东西:

create or replace function hrms.salary() 
   returns table(...) as
$Body$
Begin
  RETURN QUERY
  with pivotchart as(
    ...
  ),
  groupedresults as (
    ....
  ),
  numberofdays as(
     ...
  ),
  joinsofvalue as(
     ...
  )
  select * 
  from joinsofvalue;
end;
$Body$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)

普通 SQL 函数通常比使用RETURN QUERY.

在这种情况下,您没有BEGIN ... END,只需将查询放入函数体中并将语言更改为sql:

create or replace function hrms.salary() 
  returns table(...) as
$Body$
  -- no BEGIN here, no RETURN QUERY required
  -- just write the query 
  with pivotchart as(
    ...
  ),
  groupedresults as (
    ....
  ),
  numberofdays as(
     ...
  ),
  joinsofvalue as(
     ...
  )
  select * 
  from joinsofvalue;
$Body$
language sql;
Run Code Online (Sandbox Code Playgroud)

至于你的错误:

错误:列引用“employeeid”不明确

详细信息准确地告诉您该错误的原因是什么:

详细信息:它可以引用 PL/pgSQL 变量或表列。

您有一个名为 的参数employeeid ,并且有一个名为 的列employeeid。在查询中:

  groupedresults as (
    select employeeid ,
           sum(present) as present,
           sum(absent) as absent,
           sum(holiday) as holiday,
           sum(leave) as leave
    from pivotchart
    group by employeeid
  )
Run Code Online (Sandbox Code Playgroud)

employeeid可以引用表的列或参数。

有关名称解析的更多详细信息,请参阅手册

通常的命名约定(正如我在第一个示例中使用的那样)是在参数前添加一些前缀,这样就不会出现名称冲突。

您还可以在表的列名前面加上前缀,以避免名称冲突:

  groupedresults as (
    select p.employeeid ,
           sum(p.present) as present,
           sum(p.absent) as absent,
           sum(p.holiday) as holiday,
           sum(p.leave) as leave
    from pivotchart as p
    group by p.employeeid
  )
Run Code Online (Sandbox Code Playgroud)

但通常最好使用与列名称不冲突的参数和变量名称。