2009-03-02 21 views
8

1: n ilişkisi olan iki tablo var: "content" ve "versioned-content-data" (örneğin, bir makale varlığı ve bu makalenin oluşturduğu tüm sürümler) . Her "içeriğin" en üst sürümünü görüntüleyen bir görünüm oluşturmak istiyorum.Bir SQL alt sorguyu bir birleştirmeye dönüştürme

 
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)))

alt sorgu belirli bir öğeyi en yüksek sürümünü ayıklar aynı tabloya bir sorgu geçerli:

Şu anda (basit bir alt sorgu ile) bu sorguyu kullanın. Sürümdeki öğelerin aynı fk_idothertable değerine sahip olacağına dikkat edin.

SQL Server ben bu sorgunun bir dizinli görünüm oluşturmaya çalıştık ama subqueries endeksli görünümleri izin verilmez çünkü ben açamıyorum görünüyor. Yani ... İşte benim sorum ... Bu sorguyu JOINs ile bir tür sorguya dönüştürmenin bir yolunu düşünebilir misiniz?

  • subqueries
  • ortak tablo ifadeleri
  • türetilmiş tablo
  • HAVING cümleleri

çaresizim: endeksli görünümleri içeremez gibi

görünüyor. Başka bir fikriniz var :-)

Çok teşekkürler!

+0

alt sorgunuz doğru mu? Ben sadece bir tablo başvurulan –

+0

Evet, aynı fk_idothertable aynı fk_idothertable – sachaa

+0

btw paylaşım öğesinin ayıklamak aynı tablonun bir alt sorgu olduğunu ... fk_idothertable – sachaa

cevap

13

Bu muhtemelen gelmeyecek Tablo zaten üretim aşamasındaysa, ancak bunu modellemenin doğru yolu, versiyon = 0'ı kalıcı versiyon yapmak ve her zaman OLDER malzemesinin versiyonunu arttırmaktır.Eğer yeni bir sürüm eklediğinizde Yani söyleyebilirim:

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

Sonra bu sorgu sadece

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

yok subqueries, hiçbir MAX toplama olacaktır. Mevcut sürümün ne olduğunu her zaman biliyorsunuz. Yeni kaydı eklemek için maksimum (versiyon) seçmeniz gerekmez.

+1

Çok akıllı bir fikir.Teşekkürler Joe! – sachaa

+0

Çok düzgün! –

-1

Bunu beğendi ... Sanırım alt sorgudaki 'mytable' farklı bir gerçek tabloydu ... bu yüzden bunu mytable2 olarak adlandırdım. Eğer aynı masa olsaydı, bu hala işe yaradı, ama sonra fk_idothertable'ın sadece 'id' olacağını hayal ediyorum.


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 

Umut bu

+0

Alt sorgu aslında belirli bir öğenin en yüksek sürümünü ayıklayan aynı tabloya yönelik bir sorgudur. Aynı sürüm öğelerin aynı fk_idothertable değerine sahip olacağına dikkat edin. – sachaa

0

Bunun olacağını ne kadar etkili bilmiyorum yardımcı olur, ancak:

 
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

Bir gruba ihtiyacınız var. –

+0

Ama yine de ... Bu sorgu BY BY ile bile temelde tüm liste öğeleri mytable + her öğenin maksimum sürümünü döndürür. Sadece en yüksek versiyona sahip ürünleri iade etmez. – sachaa

0

Sen MAX tarafından grubunu yapan bir tablo diğer adı yapabilmek olabilirdi. Böyle

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

Belki bir şey: Bu gibi görünebilir

? Sadece bir tahmin

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

Cevabınız için teşekkür ederiz. Çözümünüzün zarafetini gerçekten çok beğendim, ancak çalıştırdığımda: Sütun 'mytable.id', bir toplama işlevinde veya GROUP BY deyiminde bulunmadığından seçme listesinde geçersizdir. Başka bir fikrin var mı? – sachaa

+0

SELECT içindeki tüm alanları GROUP BY - AFAIK'e standart olarak eklemeniz yeterlidir, ancak gerektirmeyen DBMS'ler vardır. – jpalecek

+0

Bunu yaparsam, başlıklar sürümler arasında değiştiğinde, bu öğe (aynı fk_idothertable ile) sonuçlarda iki kez görünecektir (farklı başlık + farklı sürüm) – sachaa

0

Ben FerranB yakındı ama oldukça gruplama sağ yoktu düşünüyorum:

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

Teşekkürler Mark Bu sorgu doğru sonuçları döndürür, ancak bir "ortak tablo ifadesi" kullandığından SQL Server'da endeksli bir görünüm oluşturmak için benim için geçerli değil – 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). 
İlgili konular