2009-03-02 23 views
8

"content"と "versioned-content-data"(たとえば、アーティクルエンティティとそのアーティクルで作成されたすべてのバージョン)という1対nの関係を持つ2つのテーブルがあります。 。私は各 "コンテンツ"のトップバージョンを表示するビューを作成したいと思います。SQLサブクエリを結合に変換する方法

現在、私は(簡単なサブクエリで)このクエリを使用します。

 
SELECT 
    t1.id, 
    t1.title, 
    t1.contenttext, 
    t1.fk_idothertable 
    t1.version 
FROM mytable as t1 
WHERE (version = (SELECT MAX(version) AS topversion 
        FROM mytable 
        WHERE (fk_idothertable = t1.fk_idothertable)))

サブクエリが実際に特定のアイテムの最新バージョンを抽出し、同じテーブルにクエリです。バージョン管理されたアイテムは同じfk_idothertableを持つことに注意してください。

は、SQL Serverでは、私はこのクエリのインデックス付きビューを作成しようとしましたが、サブクエリがインデックス付きビューで許可されていないので、私はできないんだそうです。だから...ここに私の質問です...あなたは、このクエリをJOINsを使った何らかのクエリに変換する方法を考えることができますか?

  • サブクエリ
  • 共通テーブル式を
  • 派生テーブル
  • HAVING句

私は必死だ:インデックス付きビューを含めることはできませんように

は、それはそうです。その他のアイデアは大歓迎です:-)

ありがとう!

+0

サブクエリは正しいですか?参照しているテーブルが1つしかない –

+0

はい、同一のテーブルのサブクエリで、同じfk_idothertableを共有するアイテムの最大バージョンを抽出します – sachaa

+0

btw ... fk_idothertableはマスターテーブルの外部キーです – sachaa

答えて

13

これはおそらくないでしょうテーブルがすでに生産中の場合に助けますが、これをモデル化する正しい方法は、バージョン= 0を永続的なバージョンにして、OLDERマテリアルのバージョンを常に増やすことです。新しいバージョンを挿入したときだからあなたが言う:

UPDATE thetable SET version = version + 1 WHERE id = :id 
INSERT INTO thetable (id, version, title, ...) VALUES (:id, 0, :title, ...) 

はその後、このクエリはちょうど

SELECT id, title, ... FROM thetable WHERE version = 0 

ませサブクエリ、無MAX集約ないだろう。あなたは常に現在のバージョンが何であるか知っています。新しいレコードを挿入するためにmax(バージョン)を選択する必要はありません。

+1

非常に巧妙なアイデアありがとうジョー! – sachaa

+0

非常にきれい! –

-1

このように...私は、サブクエリの 'my​​table'が別の実際のテーブルであると仮定しています...私はそれをmytable2と呼びました。それが同じテーブルであった場合でもこれは動作しますが、fk_idothertableは単に 'id'になると想像します。


SELECT 
    t1.id, 
    t1.title, 
    t1.contenttext, 
    t1.fk_idothertable 
    t1.version 
FROM mytable as t1 
    INNER JOIN (SELECT MAX(Version) AS topversion,fk_idothertable FROM mytable2 GROUP BY fk_idothertable) t2 
     ON t1.id = t2.fk_idothertable AND t1.version = t2.topversion 

希望これは

+0

サブクエリは、実際には特定のアイテムの最高バージョンを抽出する同じテーブルへのクエリです。バージョン管理された同じアイテムには同じfk_idothertableが付いていることに注意してください。 – sachaa

0

を助け、私は、これは可能だろうか効率的に知っているが、しません:

 
SELECT t1.*, t2.version 
FROM mytable AS t1 
    JOIN (
     SElECT mytable.fk_idothertable, MAX(mytable.version) AS version 
     FROM mytable 
    ) t2 ON t1.fk_idothertable = t2.fk_idothertable 
+0

でグループが必要です。 –

+0

しかし、まだ... GROUP BYでもこのクエリは基本的にすべてのリスト項目をmytable +各項目の最大バージョンから返します。最高のバージョンのアイテムを返すだけではありません。 – sachaa

0

あなたはMAXでグループを行い、テーブルの別名作ることができるかもしれません。このような

SELECT 
    t1.id, 
    t1.title, 
    t1.contenttext, 
    t1.fk_idothertable 
    t1.version 
FROM mytable as t1 JOIN 
    (SELECT fk_idothertable, MAX(version) AS topversion 
    FROM mytable 
    GROUP BY fk_idothertable) as t2 
ON t1.version = t2.topversion 
3

多分何か:それは次のようになります

SELECT 
    t2.id, 
    t2.title, 
    t2.contenttext, 
    t2.fk_idothertable, 
    t2.version 
FROM mytable t1, mytable t2 
WHERE t1.fk_idothertable == t2.fk_idothertable 
GROUP BY t2.fk_idothertable, t2.version 
HAVING t2.version=MAX(t1.version) 

ちょうど野生の推測...

+0

お返事ありがとうございます。 カラム 'mytable.id'は、集計関数またはGROUP BY句に含まれていないため、選択リストでは無効です。 他のアイデアはありますか? – sachaa

+0

標準で必要とするSELECTのGROUP BY - AFAIKにすべてのフィールドを追加するだけですが、それを必要としないDBMSがあります。 – jpalecek

+0

タイトルを変更するたびに、このアイテム(同じfk_idothertable)が結果に2回追加されます(異なるタイトル+別のバージョン) – sachaa

0

私はFerranBが近かったと思いますが、かなり右のグループがありませんでした:

with 
latest_versions as (
    select 
     max(version) as latest_version, 
     fk_idothertable 
    from 
     mytable 
    group by 
     fk_idothertable 
) 
select 
    t1.id, 
    t1.title, 
    t1.contenttext, 
    t1.fk_idothertable, 
    t1.version 
from 
    mytable as t1 
    join latest_versions on (t1.version = latest_versions.latest_version 
     and t1.fk_idothertable = latest_versions.fk_idothertable); 

M

+0

Thanks Mark。このクエリは正しい結果を返しますが、 "共通テーブル式"を使用していますSQL Serverでインデックス付きビューを作成するために私にとっては有効ではありません。 – sachaa

0
If SQL Server accepts LIMIT clause, I think the following should work: 
SELECT 
    t1.id, 
    t1.title, 
    t1.contenttext, 
    t1.fk_idothertable 
    t1.version 
FROM mytable as t1 ordery by t1.version DESC LIMIT 1; 
(DESC - For descending sort; LIMIT 1 chooses only the first row and 
DBMS usually does good optimization on seeing LIMIT). 
関連する問題