Боковой обходной путь: передача аргумента в функцию, возвращающую множество, из другого места в запросе - PullRequest
0 голосов
/ 08 ноября 2011

В 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 и т. д. и оказались пустыми, каждая комбинация, кажется, зацикливается на вечность, вызывая похожесть () вместо того, чтобы вызывать ее один раз и присоединяться к ней.

1 Ответ

2 голосов
/ 09 ноября 2011

В вашем примере есть несколько проблем.

  • Вы пытаетесь передать параметр в функцию, одновременно присоединяясь к его результату, что повлияет на то, что подается в функцию.на первом месте.Такой замкнутый круг никогда не может работать на принципале.

Сообщение об ошибке совершенно ясно об этом:

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.
  • Ваш синтаксис противоречив.Псевдоним для некоторых таблиц, но не для других.Начните с того, чтобы исправить это.Возможно, вы путаете себя.
  • Вы смешиваете идентификаторы weighting и weightings.Предположительно опечатки.
  • Не называйте IN-параметры, если вы все равно будете ссылаться на них с пометкой $ n .Это только создает возможные конфликты имен.Или используйте имена, которые не могут быть перепутаны, например, с префиксом, который выделяет их.

Я превратил вашу демонстрацию в нечто, что будет работать:

-- 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);

Может быть, это можетвсе будет упрощено на более низком уровне.

...