PostgreSQL ERROR: подзапрос в FROM не может ссылаться на другие отношения того же уровня запроса - PullRequest
0 голосов
/ 13 октября 2011

У меня непомерное количество проблем с использованием CTE в качестве аргументов для вызова функции PostgreSQL, и никакое количество рефакторинга в подзапросы, похоже, не поможет; Я получаю либо subquery in FROM cannot refer to other relations of same query level, либо function expression in FROM cannot refer to other relations of same query level. Упрощенный SQL:

create type similarity as (
  distance    float,
  explanation text
);

create or replace function similarity(my_user_id int)
returns table(user_id int, distance float, explanation hstore) as $$

  with factors as (
    select users.id as user_id, demographics.gender
    from users 
    join demographics on users.id = demographics.user_id),

  my_factors as (
    select user_id, gender
    from factors 
    where user_id = $1),

  similarities as (
    select factors.user_id, sim.distance, sim.explanation
    from factors, my_factors, similarity_gender(my_factors.gender, factors.gender) as sim)

  select user_id, distance, explanation from similarities;
$$ language sql stable strict;


create or replace function similarity_gender(my_gender text, other_gender text) returns similarity as $$
  declare
    distance  float;
    sim       similarity;
  begin
    if my_gender is null or other_gender is null then
      distance = 0.9;
    elsif (my_gender = other_gender) then
      distance = 0.0;
    else
      distance = 1.0;
    end if;

    sim.distance     = distance;
    sim.explanation  = hstore('gender', cast(sim.distance as text));
    return sim;
  end;
$$ language plpgsql immutable;

1 Ответ

2 голосов
/ 14 октября 2011

Для отладки я создал тестовый сценарий:
Вы должны были включить это в свои настройки в вопросе.

-- drop schema x CASCADE;
create schema x
create table x.users(id int);
create table x.demographics (user_id int, gender text);

INSERT INTO x.users VALUES (1),(2),(3),(4),(5);
INSERT INTO x.demographics VALUES (1, 'm'),(2, 'f'),(3, 'm'),(4, 'f'),(5, 'm');

Это работает сейчас, после некоторых исправлений:

create type x.similarity as (
  distance    float,
  explanation text
);

create or replace function x.similarity_gender(my_gender text, other_gender text)
returns x.similarity as $$
  declare
    distance  float;
    sim       x.similarity;
  begin
    if my_gender is null or other_gender is null then
      distance = 0.9;
    elsif (my_gender = other_gender) then
      distance = 0.0;
    else
      distance = 1.0;
    end if;

    sim.distance     = distance;
    sim.explanation  = hstore('gender', cast(sim.distance as text));
    return sim;
  end;
$$ language plpgsql immutable;


create or replace function x.similarity(my_user_id int)
returns table(user_id int, distance float, explanation text) as $$

  with factors as (
    select u.id as user_id, d.gender
    from x.users u
    join x.demographics d on u.id = d.user_id),

  my_factors as (
    select f.user_id, f.gender
    from factors  f
    where f.user_id = $1),

  similarities as (
    select f.user_id, x.similarity_gender(m.gender, f.gender) AS sim
    from factors f, my_factors m)

  select s.user_id, (s.sim).distance, (s.sim).explanation
    from similarities s;
$$ language sql stable strict;

Звоните:

test=# SELECT * FROM x.similarity(2);
 user_id | distance |  explanation
---------+----------+---------------
       1 |        1 | "gender"=>"1"
       2 |        0 | "gender"=>"0"
       3 |        1 | "gender"=>"1"
       4 |        0 | "gender"=>"0"
       5 |        1 | "gender"=>"1"

Основные баллы

  • Сначала создайте функцию, в вашей настройке последовательность выполнения отменена
  • При сходстве функций необходимо указывать имена столбцов, чтобы избежать конфликтов имен с параметрами OUT с одинаковыми именами (user_id, distance, explanation).
  • Ваше сходство с CTE было искажено. Я вытащил вызов функции Similarity_gender (..) вверх в список SELECT. Чтобы не звонить дважды, я разделил его на следующем шаге.
  • Используйте скобки для доступа к полям составных типов. Обратитесь к подробному руководству здесь .
  • Возвращаемый тип функции схожести () имел ошибку: explanation hstore. Должно быть explanation text.
...