2

私は次のように3つの大きなテーブルを持っています...

property
--------
property_id
other_prop_data

transfer_property
-----------------
property_id
transfer_id

transfer
--------
transfer_id
contract_date
transfer_price

'2012-01-01'と'2012-06-30'の間に発生したすべての転送の一意のプロパティIDのリストを返したいです。これが私がこれまでに持っているコードです...

SELECT *
FROM property p
JOIN
(
  SELECT t.transfer_id, t.contract_date, t.transfer_price::integer, tp.property_id
  FROM transfer t
  LEFT JOIN transfer_property tp ON tp.transfer_id = t.transfer_id
  WHERE t.contract_date BETWEEN '2012-01-01' AND '2012-06-30'
) transfer1 ON transfer1.property_id = p.property_id

AND NOT EXISTS
(
  SELECT transfer2.transfer_id
  FROM
  (
    SELECT t.transfer_id, t.contract_date, t.transfer_price::integer, tp.property_id
    FROM transfer t
    LEFT JOIN transfer_property tp ON tp.transfer_id = t.transfer_id
    WHERE t.contract_date BETWEEN '2012-01-01' AND '2012-06-30'
  ) AS transfer2
  WHERE transfer2.property_id = transfer1.property_id
  AND transfer2.contract_date > transfer1.contract_date
)

これは(私が思うに)機能しますが、非常に遅いです。

私はいくつかの同様のクエリを見つけました... https://stackoverflow.com/questions/tagged/greatest-n-per-group ...しかし、私が見つけたもののほとんどは、リレーショナルに結合されたのではなく、同じテーブルとの自己結合でした上記のテーブル。

MySQLでユーザー変数を使用できることは知っていますが、PostgreSQLでこれを行う方法、またはこの場合の理想的なソリューションであるかどうかはわかりません。

このクエリを改善する方法(または上記の私の方法とはまったく異なる方法を使用してそれを行う方法)について誰かが何か提案がありますか?

どんな助けでも大歓迎です。ありがとう!

よろしく、

クリス

PS:DISTINCTとMAXのバリエーションも試しましたが、私が使用していた方法で最新の日付のレコードを選択しているとは確信していません。

編集:申し訳ありませんが、PGADMIN1.12.3でクエリを実行していることも追加する必要があります

4

3 に答える 3

1

ROW_NUMBER() OVERPostgreSQLで使用してみてください。SQLFiddleのを次に示します。

SELECT *
FROM property p
JOIN
(
  SELECT t.transfer_id, t.contract_date, 
         t.transfer_price::integer, tp.property_id,
         row_number() over 
           (PARTITION BY tp.property_id 
            ORDER BY t.contract_date desc) as rn
  FROM transfer t
  LEFT JOIN transfer_property tp 
        ON tp.transfer_id = t.transfer_id
  WHERE t.contract_date BETWEEN '2012-01-01' 
                            AND '2012-06-30'
) transfer1 
       ON transfer1.property_id = p.property_id
where transfer1.rn = 1
于 2012-09-12T06:28:34.797 に答える
0

スケルトンテーブルが与えられた場合:

create table property( property_id serial primary key );

create table transfer(
    transfer_id serial primary key,
    contract_date date not null
);

create table transfer_property (
    property_id integer references property(property_id),
    transfer_id integer references transfer(transfer_id)
);

およびデータ:

insert into property
select nextval('property_property_id_seq') 
from generate_series(1,10);

insert into transfer 
select nextval('transfer_transfer_id_seq'), 
       DATE '2012-01-01' + x * INTERVAL '1 month'
from generate_series(1,10) x;

-- Repeat this 4 or 5 times to produce a pile of duplicate entries
insert into transfer_property (transfer_id,property_id)
select transfer_id, property_id
from property cross join transfer
order by random()
limit 40;

使用する:

select distinct property_id 
from transfer_property tp inner join transfer t on (tp.transfer_id = t.transfer_id)
where t.contract_date between  '2012-01-01' and '2012-06-30';

不十分/誤解?サンプルデータと、意味のある関係と期待される結果を示す実際のスキーマを投稿してください

于 2012-09-12T11:07:08.590 に答える
0

「「2012-01-01」と「2012-06-30」の間に発生したすべての転送の一意のプロパティIDのリストを返したいのですが。」

私には、それは次のように見えます。

SELECT DISTINCT tp.property_id
  FROM transfer t
  JOIN transfer_property tp ON tp.transfer_id = t.transfer_id
  WHERE t.contract_date BETWEEN '2012-01-01' AND '2012-06-30'
     ;

これをCTEまたはサブクエリに入れると、次のようになります。

WITH x1 AS (
      SELECT DISTINCT tp.property_id AS property_id
      FROM transfer t
      JOIN transfer_property tp ON tp.transfer_id = t.transfer_id
      WHERE t.contract_date BETWEEN '2012-01-01' AND '2012-06-30'
      )
SELECT ...
FROM property p
JOIN x1 ON x1.property_id = p.property_id
    ;

NOTEXISTSサブクエリの目的がわかりません。あなたはMAXだけに興味がありますか?

更新:(タイトルから)maxdateのみが必要なようです。存在しない構成、またはサブクエリのこのMAX(...)によって実行できます。お気に入り ... :

WITH m1 AS (
      SELECT DISTINCT tp.property_id AS property_id
        , MAX(t.contract_date) AS contract_date
      FROM transfer t
      JOIN transfer_property tp ON tp.transfer_id = t.transfer_id
      WHERE t.contract_date BETWEEN '2012-01-01' AND '2012-06-30'
        GROUP BY tp.property_id
      )
SELECT ...
FROM property p
JOIN m1 ON m1.property_id = p.property_id
    ;
于 2012-09-12T11:26:24.947 に答える