横向解决方法:将参数从查询中的其他位置传递给集合返回函数

Posted

技术标签:

【中文标题】横向解决方法:将参数从查询中的其他位置传递给集合返回函数【英文标题】:Lateral workaround: Passing an argument to a set-returning function from elsewhere in the query 【发布时间】:2011-11-08 16:36:48 【问题描述】:

在 PostgreSQL 中,我正在尝试加入一个集合返回函数,该函数需要查询中其他地方的参数。我怎样才能重写这个查询,这样它就不会产生“对 FROM 子句条目的无效引用?因为我理解它,所写的查询需要 LATERAL 支持,而 Postgres 没有。

drop table if exists questions;
create table questions (
  id int not null primary key,
  user_id int not null
);
insert into questions
  select generate_series(1,1100), (random()*20000)::int;

drop table if exists users;
create table users (
  id int not null primary key
);
insert into users select generate_series(1, 20000);

drop function if exists question_weightings();
create function question_weightings()
returns table (question_id int, weighting int) as $$
  select questions.id, (random()*10)::int
  from questions;
$$ language sql stable;

drop function if exists similarity(int);
create function similarity(weighting int)
returns table (user_id int, score int) as $$
  select users.id,  (random() * $1)::int
  from users;
$$ language sql stable;

select questions.id, qw.weightings
from questions
join question_weightings() as qw
on qw.question_id = questions.id
join similarity(qw.weighting) as sim
on sim.user_id = questions.user_id;

我怀疑答案在这个帖子的某个地方: http://archives.postgresql.org/pgsql-general/2011-08/msg00482.php。 但是我玩过 CTE、子查询、OFFSET 0 等的各种组合,结果一无所获;每个组合似乎都在循环调用similarity(),而不是调用一次并加入它。

【问题讨论】:

【参考方案1】:

您的示例中有几个问题。

您尝试将参数提供给函数,同时加入其结果,这将首先影响提供给函数的内容。那种恶性循环是根本行不通的。

错误信息很清楚:

ERROR:  invalid reference to FROM-clause entry for table "qw"
LINE 5: join similarity(qw.weighting) as sim on sim.user_id = questi...
                        ^
HINT:  There is an entry for table "qw", but it cannot be referenced from this part of the query.

但还有更多:

您不能将整个 SET OF 值提供给采用 一个 值的函数。 您不能将使用 random() 的函数定义为 STABLE。 您的语法不一致。某些表的别名,但不是其他表的别名。首先理顺它。可能你自己搞糊涂了。 您将标识符weightingweightings 混合在一起。可能是拼写错误。 如果要使用 $n 符号来引用 IN 参数,请不要命名它们。这只会产生可能的命名冲突。或者使用不会混淆的名称,例如使用前缀将它们区分开来。

我把你的演示变成了可以工作的东西:

-- DROP SCHMEMA x CASCADE;
CREATE SCHEMA x

CREATE TABLE x.questions (id int PRIMARY KEY, user_id int NOT NULL);
INSERT INTO x.questions SELECT generate_series(1,11), (random()*20000)::int;

CREATE TABLE x.users (id int PRIMARY KEY);
INSERT INTO x.users SELECT generate_series(1, 200);

CREATE FUNCTION x.question_weighting()
  RETURNS TABLE (question_id int, weighting int) AS 
$BODY$
SELECT q.id, (random()*10)::int
FROM   x.questions q;
$BODY$
  LANGUAGE sql;

CREATE FUNCTION x.similarity(int)
  RETURNS TABLE (user_id int, score int) AS
$BODY$
  SELECT u.id, (random() * $1)::int
  FROM   x.users u;
$BODY$
  LANGUAGE sql;

WITH qqw AS (
    SELECT q.id, q.user_id, qw.weighting
    FROM   x.questions q
    JOIN   x.question_weighting() qw ON qw.question_id = q.id
    -- WHERE  ??
    )
SELECT id, weighting
FROM   qqw
JOIN   (
    SELECT *
    FROM   x.similarity((
        SELECT weighting
        FROM   qqw      
        -- WHERE ??
        LIMIT  1
        ))
    ) sim USING (user_id);

也许这一切都可以在较低的层次上简化。

【讨论】:

还没有机会在 The Real Query 上尝试这个,但会回复并希望接受这个答案。感谢您的详细努力。是的,这个例子是草率和不一致的——我只是想把真正的查询减少到一些独立的东西。

以上是关于横向解决方法:将参数从查询中的其他位置传递给集合返回函数的主要内容,如果未能解决你的问题,请参考以下文章

javascript 点击怎么获取自己是第几个?

JPA 中的传递列表命名本机查询

如何将文件中的其他参数从 Angular 传递给 ASP.NET Core 控制器?

如何将复杂的键值参数表单视图传递给mvc中的控制器?

如何将参数从 DAO 中的方法传递到 SQL 查询?

将参数从 Excel 工作簿中的单元格传递到 SQL 查询