5

私は PostgreSQL 9 を使用しており、日付 ( ) を比較して、テーブル内RPのすべてのタプルの最近傍を検索したいのですが、次のエラーが発生します。RQt

エラー: FROM のサブクエリは、同じクエリ レベルの他のリレーションを参照できません

このクエリを使用して:

SELECT *
FROM RQ, (SELECT * FROM RP ORDER BY ABS(RP.t - RQ.t) LIMIT 1) AS RA

RQ.tサブクエリで問題があるようです。このエラーを回避するにはどうすればよいですか? サブクエリからへのアクセスを取得するにはどうすればよいRQですか?

4

2 に答える 2

6

アップデート:

LATERAL結合はそれを可能にし、Postgres9.3で導入されました。詳細:


その理由はエラーメッセージにあります。リストの1つの要素は、同じレベルFROMのリストの別の要素を参照できません。FROM同じレベルのピアには表示されません。相関サブクエリでこれを解決できます:

SELECT *, (SELECT t FROM rp ORDER BY abs(rp.t - rq.t) LIMIT 1) AS ra
FROM   rq

明らかに、RP同じように近い行のセットからどの行を選択するかは気にしないので、私も同じことをします。

ただし、リスト内のサブクエリ式は1つのSELECTしか返すことができません。テーブルに複数またはすべての列が必要な場合は、次のサブクエリ構造のようなものを使用します。両方のテーブルに 主キーが存在すると想定します。RP
id

SELECT id, t, (ra).*
FROM (
    SELECT *, (SELECT rp FROM rp ORDER BY abs(rp.t - rq.t) LIMIT 1) AS ra
    FROM   rq
    ) x;

相関するサブクエリは、パフォーマンスが悪いことで有名です。この種のクエリは、明らかに必要なものを計算しますが、式ではインデックスrp.t - rq.tを使用できないため、特に問題が発生します。テーブルが大きくなると、パフォーマンスが大幅に低下します。


この書き直されたクエリは、上のインデックスRP.tを利用できるはずです。これは、大きなテーブルではるかに高速に実行されるはずです。

WITH x AS (
    SELECT * 
         ,(SELECT t
           FROM   rp
           WHERE  rp.t <  rq.t
           ORDER  BY rp.t DESC
           LIMIT  1) AS t_pre

         ,(SELECT t
           FROM   rp
           WHERE  rp.t >= rq.t
           ORDER  BY rp.t
           LIMIT  1) AS t_post
    FROM   rq
    )
SELECT id, t
      ,CASE WHEN (t_post - t) < (t - t_pre)
            THEN t_post
            ELSE COALESCE(t_pre, t_post) END AS ra
FROM   x;

繰り返しますが、行全体が必要な場合:

WITH x AS (
    SELECT * 
         ,(SELECT rp
           FROM   rp
           WHERE  rp.t <  rq.t
           ORDER  BY rp.t DESC
           LIMIT  1) AS t_pre

         ,(SELECT rp
           FROM   rp
           WHERE  rp.t >= rq.t
           ORDER  BY rp.t
           LIMIT  1) AS t_post
    FROM   rq
    ), y AS (
    SELECT id, t
          ,CASE WHEN ((t_post).t - t) < (t - (t_pre).t)
                THEN t_post
                ELSE COALESCE(t_pre, t_post) END AS ra
    FROM   x
    )
SELECT id AS rq_id, t AS rq_t, (ra).*
FROM   y 
ORDER  BY 2;

複合型での括弧の使用に注意してください!ここでは冗長なパレンはありません。詳細については、こちらこちらのマニュアルをご覧ください。

PostgreSQL9.1でテスト済み。sqlfiddleのデモ。

于 2012-05-27T14:11:04.423 に答える
0

インデックスのない相関サブクエリは、いずれにせよクロス結合を実行します。したがって、クエリを表現する別の方法は次のとおりです。

select rp.*, min(abs(rp.t - rq.t))
from rp cross join
     rq
group by <rp.*> -- <== need to replace with all columns

もう少し複雑な別の方法があります。これには、累積合計を使用する必要があります。

これがアイデアです。すべての rp 値と rq 値を一緒に結合します。次に、最も近い rp 値でそれらを列挙します。つまり、rp のフラグを作成し、累積和を取ります。その結果、2 つの rp 値の間のすべての rq 値は、同じ rp インデックスを持ちます。

与えられた rq 値に最も近い値は、rq 値と同じかそれ以上の rp インデックスを持ちます。rq_index の計算には累積合計が使用されます。

次のクエリはこれをまとめたものです。

with rqi as (select t.*, sum(isRQ) over (order by t) as rq_index
             from (select rq.t, 0 as isRP, <NULL for each rp column>
                   from rq
                   union all
                   select rq.t, 1 as isRP, rp.* 
                   from rp
                  ) t
            ) t
select rp.*,
       (case when abs(rqprev.t - rp.t) < abs(rqnext.t - rp.t)
             then abs(rqprev.t - rp.t)
             else abs(rqnext.t - rp.t)
        end) as closest_value
from (select *
      from t
      where isRP = 0
     ) rp join
     (select *
      from t
      where isRP = 1
     ) rqprev
     on rp.rp_index = rqprev.rp_index join
     (select *
      from t
      where isRP = 1
     ) rqnext
     on rp.rp_index+1 = rpnext.rq_index

このアプローチの利点は、相互結合や相関サブクエリがないことです。

于 2012-05-28T01:22:21.790 に答える