sql'yi her kullanıcı için en son kayıt tarihi için nasıl sorgularım


228

Bir kullanıcı oturum açtığında bir koleksiyon girişleri olan bir tablo var.

username, date,      value
--------------------------
brad,     1/2/2010,  1.1
fred,     1/3/2010,  1.0
bob,      8/4/2009,  1.5
brad,     2/2/2010,  1.2
fred,     12/2/2009, 1.3

etc..

Her kullanıcı için bana en son tarihi verecek bir sorguyu nasıl oluştururum?

Güncelleme: En son tarihe uygun bir değere sahip olmam gerektiğini unuttum.


7
Hangi veritabanını kullanıyorsunuz? MySQL, SQL-Server, Oracle, ...?
Peter Lang

1
En son tarihe sahip olan değere mi, maksimum değer VE maksimum tarihe mi ihtiyacınız var?
Matthew Jones

Yanıtlar:


381
select t.username, t.date, t.value
from MyTable t
inner join (
    select username, max(date) as MaxDate
    from MyTable
    group by username
) tm on t.username = tm.username and t.date = tm.MaxDate

3
Postgresql ile çalışırken bu sürüm iç birleşim yerine IN (alt sorgu) kullanmaktan daha hızlı olur mu?
TheOne

3
Tecrübelerim olarak, iç birleşimi kullanmak koşuldan daha hızlı
dada

14
Bu yaklaşıma dikkat edin: tarihte birden fazla kaydı varsa kullanıcı başına birden fazla satır max(date)döndürebilir ( birden fazla kayda katılacak bir tarih döndürür). Bu sorunu önlemek için @ dotjoe çözümünün kullanılması tercih edilir: stackoverflow.com/a/2411763/4406793 .
Marco Roy

@RedFilter Bu benim sorunum için mükemmel çalıştı. Böyle bir teknik sorgu için çok teşekkürler. Bu arada, belirli bir tarih için birden fazla sonuç almaktan kaçınmak için tarih yerine tarih saatini kullandım
Muhammad Khan

neden 've t.date = tm.MaxDate' grubunun yeterli olmayacağını düşünüyorsunuz?
duldi

126

Pencere işlevlerini kullanma (Oracle, Postgres 8.4, SQL Server 2005, DB2, Sybase, Firebird 3.0, MariaDB 10.3'te çalışır)

select * from (
    select
        username,
        date,
        value,
        row_number() over(partition by username order by date desc) as rn
    from
        yourtable
) t
where t.rn = 1

1
Hangi Sybase ürün / versiyonunu netleştirmeye değer. Sybase ASE 16 üzerinde çalışmaz.
Levant

2
Bu yaklaşımın en büyük yararı, bölüm başına her zaman yalnızca bir satır döndürülmesinin garanti edilmesidir ( usernamebu durumda) ve hatta benzersiz bir "düzenlenebilir" alan gerektirmez ( max(date)diğer yanıtlarda yer almak gibi).
Marco Roy

1
@MarcoRoy'un söylediklerine bir şey eklemek için, aynı maksimum tarihe sahip birden fazla kaydınız varsa, sorguyu değiştirirseniz, hata ayıkladığınız zaman olduğu gibi, farklı bir kayıt 1 satır sayısı alabilir, bu nedenle sonuçlar tutarsız olabilir. Ama gerçekten umursamadığınız sürece, bu bir sorun olmamalı. PK'yi tarihten sonra eklerseniz bu çözülebilir. Örneğin: order by date desc, id desc).
Andrew

40

Geliştiricilerin çoğunun, büyük veriler üzerindeki etkisini dikkate almadan satır içi bir sorgu kullandığını görüyorum.

Basitçe, bunu şu şekilde yapabilirsiniz:

SELECT a.username, a.date, a.value
FROM myTable a
LEFT OUTER JOIN myTable b
ON a.username = b.username 
AND a.date < b.date
WHERE b.username IS NULL
ORDER BY a.date desc;

3
aslında bu sadece çoğaltmalar için geçerlidir, eğer 2'den fazla değeriniz varsa, a.date <b.date koşulu çalışmaz, yani, LEFT OUTER JOIN ile çalışma fikri önemli olsa da, genel bir çözüm değildir. Bu cevapta bir şey.
iversoncru

İlginçtir, Sybase ASE 16 daha küçük (<10k satır) tablolar için iyi çalışır, ancak daha büyük olanlarla (> 100k satır) asılıdır ... Bunun ilişkisel DB'lerin mükemmel olması gereken mükemmel bir örnek olacağını düşündüm ...
levant pied

1
@levantpied ... Evet daha büyük veri kümelerinde sol birleşim pahalı. Mümkünse bir şekilde işlemek için filtre koşulunu birleştirerek kendisine bir performans ayarı yapabilirsiniz.
sujeet

21

Kullanıcının maksimum tarihini içeren tüm satırı almak için:

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)

1
MySQL için çalışıyor
School Boy

1
Belirli bir kullanıcı için aynı tarihte birden fazla kayıt varsa, bunun size kopyalar vereceğini unutmayın. Bunu isteyebilir veya istemeyebilirsiniz.
Andrew

Bu sql yan tümcesi ile Oracle yavaş, endeksi kullanmaz
meadlai

9
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)

4
Bu başka bir olası çözüm olsa da, normalde bunu çözmek için iyi bir yol değildir. Bunu yapmak, iç sorgunun tablodaki her ad için bir kez çalışmasına neden olarak, önemli boyuttaki herhangi bir tablo için büyük bir yavaşlamaya neden olur. Where yan tümcesindeki ilk sorgudan bir öğesi olmayan ayrı bir sorgu yapmak, sonra iki tabloyu birleştirmek genellikle daha hızlı olur.
Scott Chamberlain

Bu, uygulamaya özel olmayan daha anlaşılabilir çözümlerden biri olmanın güzel bir özelliğine sahiptir.
Michael Szczepaniak

7

Deneyimlerime göre en hızlı yol, tabloda daha yeni bir satır olmayan her satırı almaktır.

Başka bir avantaj, kullanılan sözdiziminin çok basit olması ve sorgunun anlamının anlaşılması oldukça kolaydır (tüm satırları, dikkate alınan kullanıcı adı için daha yeni bir satır olmayacak şekilde alın).

VAR DEĞİL

SELECT username, value
FROM t
WHERE NOT EXISTS (
  SELECT *
  FROM t AS witness
  WHERE witness.username = t.username AND witness.date > t.date
);

SATIR NUMARASI

SELECT username, value
FROM (
  SELECT username, value, row_number() OVER (PARTITION BY username ORDER BY date DESC) AS rn
  FROM t
) t2
WHERE rn = 1

İÇ BİRLEŞİM

SELECT t.username, t.value
FROM t
INNER JOIN (
  SELECT username, MAX(date) AS date
  FROM t
  GROUP BY username
) tm ON t.username = tm.username AND t.date = tm.date;

SOL DIŞ KATILMA

SELECT username, value
FROM t
LEFT OUTER JOIN t AS w ON t.username = w.username AND t.date < w.date
WHERE w.username IS NULL

NOT EXISTS sürümünü anlamakta güçlük çekiyorum. Alt sorgu bölümünde bir toplama yok mu? Bunu masamda çalıştırırsam, sadece tablodaki 40 çalışandan 3 çalışan kaydı alırım. En az 40 kayıt almalıyım. İç sorguda, kullanıcı adıyla da eşleşmemeliyiz?
Narshe

Aşağıdakileri kullanarak benim için çalışıyor:SELECT username, value FROM t WHERE NOT EXISTS ( SELECT * FROM t AS witness WHERE witness.date > t.date AND witness.username = t.username );
Narshe

Ben VAR DEĞİL baktım ve sadece aksine tüm kullanıcılar için daha yüksek giriş dönmek için görünüyor: "bana her kullanıcı için son tarih verecek bir sorgu".
Tasos Zervos

Haklısın, sorgumu güncelliyorum. Yorumunuz için teşekkürler! @Herhangi bir nedenden dolayı yorumlarınızı kaçırdığım için üzgünüm: / Ama kesinlikle haklısınız.
Fabian Pijcke

2

Bu, düzenlenmiş sorunuz için size doğru sonucu vermelidir.

Alt sorgu yalnızca son tarihin satırlarını bulmanızı sağlar ve dış GROUP BYbağlarla ilgilenir. Aynı kullanıcı için aynı tarih için iki giriş olduğunda, en yüksek girişe geri döner value.

SELECT t.username, t.date, MAX( t.value ) value
FROM your_table t
JOIN (
       SELECT username, MAX( date ) date
       FROM your_table
       GROUP BY username
) x ON ( x.username = t.username AND x.date = t.date )
GROUP BY t.username, t.date

1

Analitik Sıralama İşlevini de kullanabilirsiniz

    with temp as 
(
select username, date, RANK() over (partition by username order by date desc) as rnk from t
)
select username, rnk from t where rnk = 1

0
SELECT Username, date, value
 from MyTable mt
 inner join (select username, max(date) date
              from MyTable
              group by username) sub
  on sub.username = mt.username
   and sub.date = mt.date

Güncellenen sorunu ele alacaktır. İyi indeksleme ile bile büyük tablolarda çok iyi çalışmayabilir.


0
SELECT *
FROM ReportStatus c
inner join ( SELECT 
  MAX(Date) AS MaxDate
  FROM ReportStatus ) m
on  c.date = m.maxdate

0

Oracle için sonuç kümesini azalan sırada sıralar ve ilk kaydı alır, böylece en son kaydı alırsınız:

select * from mytable
where rownum = 1
order by date desc

0
SELECT DISTINCT Username, Dates,value 
FROM TableName
WHERE  Dates IN (SELECT  MAX(Dates) FROM TableName GROUP BY Username)


Username    Dates       value
bob         2010-02-02  1.2       
brad        2010-01-02  1.1       
fred        2010-01-03  1.0       

Birden fazla kullanıcının aynı tarihte siparişleri varsa bu muhtemelen işe yaramaz; brad ve bob'un 2 Ocak'ta bir emri olsaydı ne olurdu?
AHiggins

Kullanıcı adına göre gruplandırıyorum, bu yüzden işe yarayacak ve sonuçlar şöyle olacak: Kullanıcı adı Tarihler değer bob 2010-02-02 1.2 brad 2010-02-02 1.4 fred 2010-01-03 1.0
wara

0
SELECT t1.username, t1.date, value
FROM MyTable as t1
INNER JOIN (SELECT username, MAX(date)
            FROM MyTable
            GROUP BY username) as t2 ON  t2.username = t1.username AND t2.date = t1.date

4
Uygulama veya açıklama ile ilgili bir veya iki cümle, kaliteli bir cevap oluşturmak için uzun bir yol kat eder.

0

Select * from table1 where lastest_date=(select Max(latest_date) from table1 where user=yourUserName)

İç Sorgu geçerli kullanıcı için en son tarihi döndürür, Dış sorgu iç sorgu sonucuna göre tüm verileri çeker.


0

Bu yöntemi masamda bulunan her kullanıcı için son kaydı almak için kullandım. PDA cihazlarında algılanan son zamana göre satıcı için son konumu almak bir sorguydu.

CREATE FUNCTION dbo.UsersLocation()
RETURNS TABLE
AS
RETURN
Select GS.UserID, MAX(GS.UTCDateTime) 'LastDate'
From USERGPS GS
where year(GS.UTCDateTime) = YEAR(GETDATE()) 
Group By GS.UserID
GO
select  gs.UserID, sl.LastDate, gs.Latitude , gs.Longitude
        from USERGPS gs
        inner join USER s on gs.SalesManNo = s.SalesmanNo 
        inner join dbo.UsersLocation() sl on gs.UserID= sl.UserID and gs.UTCDateTime = sl.LastDate 
        order by LastDate desc

0
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)

StackOverflow'a hoş geldiniz ve yardım etmeye çalıştığınız için teşekkür ederiz. Sizinkine benzer yalnızca kod yanıtları, çözümü açıklayan yanıtlarla karşılaştırıldığında daha az takdir edilmektedir.
Yunnosch

Kaliteli cevap sağlamak için lütfen bu nasıl yanıtlanacağını okuyun.
thewaywewere

ve. her kullanıcı adı için MAX değerine dönmez, yalnızca en son tek satıra döner.
IrvineCAGuy

0

Benim küçük derleme

  • öz joiniyi yuvalanmış dahaselect
  • ama group bysize primary keyhangisinin tercih edileceğini vermiyorjoin
  • Bu anahtar verilebilir partition byile bağlantılı olarak first_value( dokümanlar )

İşte bir sorgu:

seçmek
 t. *
itibaren 
 Tablo t iç bağlantı (
  farklı olarak first_value (ID) over (GroupColumn order by DateColumn desc by partition) ID olarak seçin
  Tablodan
  burada FilterColumn = 'değer'
 ) t.ID = j.ID

Artıları:

  • whereHerhangi bir sütunu kullanarak ifadeyle verileri filtreleme
  • select filtrelenmiş satırlardaki sütunlar

Eksileri:

  • 2012'den başlayarak MS SQL Server gerekir.

0

Benim uygulama için biraz yaptım:

Sorgu aşağıdadır:

select distinct i.userId,i.statusCheck, l.userName from internetstatus 
as i inner join login as l on i.userID=l.userID 
where nowtime in((select max(nowtime) from InternetStatus group by userID));    

0

Bu, yukarıdaki cevaplardan birine benzer, ancak bence çok daha basit ve daha düzenli. Ayrıca, çapraz uygulama ifadesi için iyi bir kullanım gösterir. SQL Server 2005 ve üstü için ...

select
    a.username,
    a.date,
    a.value,
from yourtable a
cross apply (select max(date) 'maxdate' from yourtable a1 where a.username=a1.username) b
where a.date=b.maxdate

0
SELECT MAX(DATE) AS dates 
FROM assignment  
JOIN paper_submission_detail ON  assignment.PAPER_SUB_ID = 
     paper_submission_detail.PAPER_SUB_ID 

1
Bu kod, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere soruyu çözebilir, ancak gönderinizin kalitesini artırmaya yardımcı olabilir ve muhtemelen daha fazla oyla sonuçlanır. Sadece şimdi soran kişi için değil, gelecekte okuyucular için soruyu cevapladığınızı unutmayın. Lütfen açıklama eklemek için cevabınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğunu belirtin. Şu kaynaktan
double-beep

-2

Bu, kullanıcılar için en son girişlerin tümünü almak için de çalışmalıdır.

SELECT username, MAX(date) as Date, value
FROM MyTable
GROUP BY username, value

1
Merhaba, değer sütununun yan tümcesi tarafından grupta olması gerekir.
Juan Ruiz de Castilla

-4

MAX ve GROUP BY toplama işlevini kullanırsınız

SELECT username, MAX(date), value FROM tablename GROUP BY username, value

7
Düzenlemeniz yalnızca rastgele seçer value, MAX(date)satırla ilişkili olanı değil .
Alison

maksimum tarihi verir ancak kullanıcı adı ve değeri aynı kayıtta olmayabilir.
SKR
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.