2011-07-27 20 views
5

(sütun adlarını olmanın ilk satır) ile sütuna göre benzersiz kayıtları seçmek yapmak ad sütununun sonuç kümesinde her zaman benzersiz olduğunu mu? Bu örnekte sorguyu ilk Eric (w/Ruby) kaydını döndürmek istiyorum.nasıl ActiveRecord ve aşağıdaki kayıtlar Verilen Postgresql

Elimdeki en yakın şey, "(name) * ... 'de farklı olanı kullan" seçeneğini kullanmaktır, ancak bu, kayıtların tarih sütunuyla gerçekten sipariş vermek istediğimde, önce isme göre sipariş vermemi gerektirir. . Tarihe göre

  • Sipariş kayıtları aynı adı (farketmez) seçeneğini biri ile birden fazla kayıt varsa
  • ben Rails Bunu başarmak nasıl bütün sütunlar

seçin PostgreSQL üzerinde?

cevap

0

Adlar ve minimum tarihlerin bir listesini alın ve aradığınız satır kümesini elde etmek için orijinal tabloya geri ekleyin.

select 
    b.* 
from 
    (select name, min(date) as mindate from table group by name) a 
    inner join table b 
     on a.name = b.name and a.mindate = b.date 
+0

Bir "isim, min (tarih) çifti" tablosunda iki kez gösteriliyorsa, bunun benzersiz sorunları vardır. –

2

Ben Birden isimler var (bu tüm sütunlar için geçerli olacak) olduğunda satır alınır hangi umurumda değil ve tablo

SELECT * FROM table_name GROUP BY `name` ORDER BY `date` 
gibi bir sorgu yapmak basitçe ki yapıya sahiptir

veya Raylar

TableClass.group(:name).order(:date) 
+0

Bu yöntemi uygularken, aşağıdaki hatayı alıyorum: GROUP BY deyiminde "games.id" sütununun görünmesi veya –

+1

toplama işlevinde kullanılması gerekir. Aşağı çekmek yerine yapınızı daha iyi açıklayın, sorunuzu Bu hata mesajı nedeniyle doğru olmayan tek bir tablo var. Bunun yerine tam yapınızı gönderin. – Fabio

+0

+1, anlaşılırlığı ortadan kaldırmak için -1 – apneadiving

7

sen yapamaz basit .group(:name) size gruplanmamış ve unaggregate seçeceğiniz için zaman senin SQL bir GROUP BY name ürettiği için

When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions, since there would be more than one possible value to return for an ungrouped column.

böyle bir şey ile gruplamaya fazla sütun ekleme başlatırsanız:

T.group(T.columns.collect(&:name)) 

sonra tarafından gruplama olacak hangi satırı almak ve PostgreSQL (rightly IMHO) complains gerektiği konusunda d sütun, bu belirsizliğe yol açar istemediğiniz şeyler ve tüm masayı çekip bitirirsiniz ve bu sizin istediğiniz şey değildir. Gruplama probleminden kaçınmak için bir araya getirmeye çalışırsanız, farklı satırları karıştırarak sonuçlanırsınız (yani, bir satır diğer satırdan başka bir sütun gelirken bir sütun gelir) ve bu da sizin istediğiniz gibi değildir.

ActiveRecord gerçekten bu tür bir şey için oluşturulmamış, ancak biraz çaba ile isteğinize boyun eğebilirsiniz.

AR kullanıyorsunuzdur, dolayısıyla muhtemelen bir id sütununa sahipsiniz. PostgreSQL 8'iniz varsa.4 ya da daha yüksek, daha sonra window functions yerel olarak GROUP BY; iki kez pencereye ihtiyacın olacak: bir kez name/thedate çiftini anlamaya ve sadece bir tane id (sadece aynı name ve thedate ile eşleştiğinde, en eski thedate ile eşleşecek) ve böylece benzersiz bir satır olsun :

select your_table.* 
from your_table 
where id in (
    -- You don't need DISTINCT here as the IN will take care of collapsing duplicates. 
    select min(yt.id) over (partition by yt.name) 
    from (
     select distinct name, min(thedate) over (partition by name) as thedate 
     from your_table 
    ) as dt 
    join your_table as yt 
     on yt.name = dt.name and yt.thedate = dt.thedate 
) 

Sonra find_by_sql o sarın ve size nesneleri var.

Heroku'yu paylaşılan bir veritabanıyla (veya 8.4 veya üstü olmayan başka bir ortamla) kullanıyorsanız, PostgreSQL 8.3 ile sıkışmışsınız ve pencere işlevleriniz olmayacaktır. Bu durumda, muhtemelen Yakut-arazi çiftleri filtrelemek isterdim:

with_dups = YourTable.find_by_sql(%Q{ 
    select yt.* 
    from your_table yt 
    join (select name, min(thedate) as thedate from your_table group by name) as dt 
     on yt.name = dt.name and yt.thedate = dt.thedate 
}); 

# Clear out the duplicates, sorting by id ensures consistent results 
unique_matches = with_dups.sort_by(&:id).group_by(&:name).map { |x| x.last.first } 

sonra 8.3 uyumlu çözüm olabilir yinelenen name/min(thedate) çiftleri orada olmayacak eminseniz en iyi bahşin ol; Ancak, çok fazla kopya olacaksa, o zaman veritabanının, attığınız binlerce AR nesnesini oluşturmaktan kaçınmak için mümkün olduğunca fazla iş yapmasını istiyorsunuz. Belki daha güçlü PostgreSQL-Fu'lu bir başkası yanımda gelecektir ve daha güzel bir şey sunacaktır.

+0

+1! – apneadiving

+0

@apneadiving: "Meydan okumadan sonra" zorundaydım :) –

+0

Bu cevap nihayet PostgreSQL içinde bu tür bir sorgu için neler olup bittiğini anlamamı sağladı. Detaylı cevap için teşekkürler. –