2011-11-08 4 views
0

PostgreSQLでは、クエリの別の場所から引数を必要とするセットを返す関数に参加しようとしています。どのようにこのクエリを書き直すことができますかそれは私の理解では、書かれたクエリはPostgresが持っていない横方向の支持が必要でしょうか?「FROM句エントリに無効な参照が得られない。横方向の回避策:クエリの別の場所からセットを返す関数に引数を渡す

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、サブクエリ、オフセット0などのさまざまな組み合わせで遊んできましたが、空白になりました。すべての組み合わせが永遠にs imilarity()を一度呼び出すと、それに参加する代わりに

答えて

2

あなたの例にはいくつか問題があります。

  • 同時に関数にパラメータを渡して、その結果に結合しようとすると、最初に関数に渡されるものに影響します。そのような悪循環は、プリンシパルでは決して働くことはできません。

エラーメッセージがその上で、非常に明確である:

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. 

しかし、より多くのがあります:

  • あなたは値を取る関数への値のセット全体を養うことができません。
  • random()をSTABLEとして使用して関数を定義することはできません。
  • 構文が矛盾しています。あるテーブルのエイリアスですが、他のテーブルのエイリアスはありませんそれをまっすぐに開始します。たぶんあなたは混乱しているかもしれません。
  • 識別子weightingweightingsを組み合わせて使用​​します。おそらくタイプミス。
  • 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); 

は多分これは、すべての下位レベルで簡略化することができます。

+0

まだリアルクエリーでこれを試す機会はありませんでしたが、返信してうまくいけばこの回答を受け入れます。詳細な努力をいただきありがとうございます。はい、その例はぎこちなく、矛盾していました - 私は、実際のクエリをSOの自己完結型のものに絞りたいと思っていました。 –

関連する問題