我有这个功能http://rextester.com/VIHMIG61446
CREATE OR REPLACE FUNCTION myTestProcedure(namevalue character varying)
RETURNS TABLE(id integer, name character varying, isdefault boolean)
LANGUAGE plpgsql
AS $function$
BEGIN
IF EXISTS(SELECT
Domain.id,
Domain.name,
Domain.isdefault
FROM Domain
where lower(Domain.name) like namevalue)
THEN
RETURN QUERY SELECT
Domain.id,
Domain.name,
Domain.isdefault
FROM Domain
where lower(Domain.name) like namevalue;
ELSE
RETURN QUERY SELECT
Domain.id,
Domain.name,
Domain.isdefault
FROM Domain
where Domain.isdefault = true;
END IF;
END
$function$;
我正在寻找一种不重复if的整个查询的方法,所以我决定使用with as
存储结果,但它对我不起作用http://rextester.com/MVMVA73088
我应该如何使用with as
?
CREATE OR REPLACE FUNCTION myTestProcedure(namevalue character varying)
RETURNS TABLE(id integer, name character varying, isdefault boolean)
LANGUAGE plpgsql
AS $function$
BEGIN
with temporal_result as (
SELECT
Domain.id,
Domain.name,
Domain.isdefault
FROM Domain
where lower(Domain.name) like namevalue
)
IF EXISTS(temporal_result)
THEN
RETURN QUERY SELECT * from temporal_result;
ELSE
RETURN QUERY SELECT
Domain.id,
Domain.name,
Domain.isdefault
FROM Domain
where Domain.isdefault = true;
END IF;
END
$function$;
答案 0 :(得分:3)
可以完全避免if-else逻辑。等效结果可以写为单个查询。函数BOOL_AND
是一个聚合函数,如果任何值为false
,则返回false
,否则返回true
。
即使多行与lower(name) like '<namevalue>'
条件匹配,或者您有多个默认值,以下查询也能正常工作。
SELECT subquery.id, subquery.name, subquery.isdefault
FROM (SELECT d.id,
d.name,
d.isdefault,
BOOL_AND(d.isdefault) OVER () default_and
FROM domain d
WHERE lower(d.name) like 'robert' or isdefault) subquery
WHERE isdefault = default_and
至于为什么你得到IF EXISTS(temporal_result)
的错误,那不是有效的sql。在sql语句中进行此类分支是非法的。您可以做的是将第一个查询的结果保存到临时表中,并执行if-else分支引用临时表。您的存储过程的正确版本如下:
CREATE OR REPLACE FUNCTION mytestprocedure(namevalue character varying)
RETURNS TABLE(id integer, name character varying, isdefault boolean)
LANGUAGE plpgsql
AS $function$
BEGIN
CREATE TEMPORARY TABLE temporal_result as
SELECT
d.id,
d.name,
d.isdefault
FROM domain d
where lower(d.name) like namevalue
;
IF EXISTS(SELECT TRUE FROM temporal_result) THEN
RETURN QUERY SELECT * from temporal_result;
ELSE
RETURN QUERY SELECT
d.id,
d.name,
d.isdefault
FROM domain d
where d.isdefault = true;
END IF;
DROP TABLE temporal_result;
RETURN;
END;
$function$;
请注意,必须在程序结束时删除表格。
另请注意,除非引用,否则postgresql会忽略实体名称中的大/小写情况,因此在命名表/字段/函数时使用驼峰的情况通常被认为是不好的。
答案 1 :(得分:2)
我建议改为检查特殊的plpgsql变量FOUND
:
CREATE OR REPLACE FUNCTION my_test_func(namevalue varchar)
RETURNS TABLE(id integer, name varchar, isdefault boolean) AS
$func$
BEGIN
RETURN QUERY
SELECT d.id, d.name, d.isdefault
FROM domain d
WHERE lower(d.name) LIKE namevalue;
IF NOT FOUND THEN
RETURN QUERY
SELECT d.id, d.name, d.isdefault
FROM domain d
WHERE d.isdefault;
END IF;
END
$func$ LANGUAGE plpgsql STABLE;
清洁并快速。第一个查询很简单,并且尽可能快。第一个返回任何行时,永远不会执行第二个查询。相关(查看章节&#34;其他案例&#34;):
我可能会使用d.name ILIKE namevalue
并使用trigram索引支持它。参见:
第二个查询中的默认行的部分索引也可能付费。如果您可以从中获取仅索引扫描,请包含您需要检索的(少数)列作为索引列:
CREATE INDEX domain_defaults_idx ON domain (id, name, isdefault) WHERE isdefault;
是的,我们必须包含isdefault
,即使在逻辑上多余。 Postgres目前(第10页)不够聪明,无法从WHERE
条件中获得值。
如果您无法获得仅索引扫描,那么具有常量表达式的索引会更便宜:
CREATE INDEX domain_defaults_idx ON domain ((TRUE)) WHERE isdefault;
相关: