2008-12-01 12 views
7

2 tabloyu aldığımı söyle: Müşteriler ve Siparişler. Bir Müşterinin çok siparişi olabilir.SQL Bildirimi Yardımı - Her bir Müşteri için en son Siparişi Seçin

Şimdi, herhangi bir Müşteriyi son Siparişi ile göstermem gerekiyor. Bu, bir Müşterinin birden fazla siparişe sahip olması, yalnızca en son Giriş Süresine sahip Siparişi göstermesi anlamına gelir.

Bu başıma yönetilen ne kadar geçerli: tabii

SELECT a.*, b.Id 
FROM Customer a INNER JOIN Order b ON b.CustomerID = a.Id 
ORDER BY b.EntryTime DESC 

İstediğim bu değil her Müşteri, ilk son Order gösteren bir veya birden fazla Siparişler ile tüm müşteriler döndürür

. Aklım bu noktada bir rutede sıkışmıştı, bu yüzden birilerinin beni doğru yöne yönlendirebileceğini umuyorum.

Bazı nedenlerle, ben düşünüyorum MAX sözdizimini bir yerlerde kullanmalıyım, ama şimdi sadece beni kaçırıyor.

GÜNCELLEME: burada birkaç cevapları geçiyor sonra (bir sürü var!), Ben bir hata yaptım fark etti: Onun son kaydı ile herhangi Müşteri anlamına geliyordu. Yani bir emri yoksa, onu listelememe gerek yok demektir.

UPDATE2: Büyük olasılıkla başkalarına karışmamasına neden olan kendi SQL ifademi düzeltdim. Böyle

+0

Müşteriniz tablo bir OrderID sahiptir. Bu doğru mu? –

+0

Evet, SQL'de belirtildiği gibi. – alextansc

+0

Müşteri tablonuzun bir OrderID'si varsa, sorunuz mantıklı değildir. Doğru olsaydı, her siparişin farklı bir müşterisi olduğunu söylerdin. Sipariş tablonuzun Müşteri Kimliği olmadığından emin misiniz? –

cevap

8

(-

Bu :-)

GÜNCELLEME siparişleriyle sadece müşterilerine gösterir) OrderID'yi gruplandırmak istemediğiniz için. Ne gerek SEÇ TOP ile bir sipariş alt sorgu Ben zaten bir cevap kabul ettik görürken 1.

select * 
from Customers inner join Orders 
on Customers.CustomerID = Orders.CustomerID 
and OrderID = (SELECT TOP 1 subOrders.OrderID 
        FROM Orders subOrders 
        WHERE subOrders.CustomerID = Orders.CustomerID 
        ORDER BY subOrders.OrderDate DESC) 
+0

Evet, cevabın şu ana kadarki en doğru cevap olduğunu düşünüyorum, tek hata, tarihi azalan düzende sıralamamanızdır. En zariften bahsetmiyorum. :) Teşekkürler! – alextansc

+0

Önce siparişi verdim, sonra kendimi karıştırdım ve en eski düzeni istediğini düşündüm. Şimdi benim örneğimin doğru olduğunu düşündüm. –

0
SELECT Cust.*, Ord.* 
FROM Customers cust INNER JOIN Orders ord ON cust.ID = ord.CustID 
WHERE ord.OrderID = 
    (SELECT MAX(OrderID) FROM Orders WHERE Orders.CustID = cust.ID) 
+0

Sipariş, Max OrderID ile değil, farklı olabilecek Max EntryTime ile gerçekleşiyor. –

3

şey yapmalı:

SELECT X.*, Y.LatestOrderId 
FROM Customer X 
LEFT JOIN (
    SELECT A.Customer, MAX(A.OrderID) LatestOrderId 
    FROM Order A 
    JOIN (
    SELECT Customer, MAX(EntryTime) MaxEntryTime FROM Order GROUP BY Customer 
) B ON A.Customer = B.Customer AND A.EntryTime = B.MaxEntryTime 
    GROUP BY Customer 
) Y ON X.Customer = Y.Customer 

Bu aynı müşteri için iki emir sağlamak için MAX(OrderID) alt sorgu Y neden kullanıldığı ise aynı entryTime, sahip olabileceğini varsayar sadece Müşteri başına bir kez gerçekleşir. Tüm müşterileri göstermek istediğinizi belirttiğiniz için LEFT JOIN kullanılır, çünkü herhangi bir sipariş almadıysa, SonOrderId NULL olacaktır.

Bu yardımcı olur umarız!

SELECT A.Customer, MAX(A.OrderID) LatestOrderId 
FROM Order A 
JOIN (
    SELECT Customer, MAX(EntryTime) MaxEntryTime FROM Order GROUP BY Customer 
) B ON A.Customer = B.Customer AND A.EntryTime = B.MaxEntryTime 
GROUP BY Customer 
+0

Bu çözüm, OP tarafından seçilen olandan çok daha hızlıdır. –

0

şey gibi: Sana MAX kullanmak istiyorsunuz sanmıyorum

SELECT 
    a.* 
FROM 
    Customer a 
    INNER JOIN Order b 
     ON a.OrderID = b.Id 
     INNER JOIN (SELECT Id, max(EntryTime) as EntryTime FROM Order b GROUP BY Id) met 
      ON 
      b.EntryTime = met.EntryTime and b.Id = met.Id 
6

, ben bu biraz daha sezgisel olduğunu düşünüyorum:

select  a.* 
      ,b.Id 

from  customer a 

inner join Order b 
on   b.CustomerID = a.Id 

where  b.EntryTime = (select max(EntryTime) 
          from Order 
          where Id = b.Id 
         ); 

Yürütme farkını görmek için bir yürütme planı aracılığıyla böyle bir şey çalıştırmak zorundayım, ancak TOP işlevinin gerçekte yapıldığı ve "siparişi" kullanarak pahalı olabileceği durumlarda, maksimum (EntryTime) kullanımının olduğuna inanıyorum. Bunu çalıştırmak için en iyi yol olurdu.

+0

Sorgunuzu denedim ve aynı sonucu döndürdüğünü buldum. Güzel! Cevabımı şimdilik değiştirmeyeceğim, test etmek istediğim birkaç cevap daha var. Ama, cevabınızı şimdilik oylamaya çalışacağım. :) – alextansc

+0

Şüphesiz, alt sorgunun nerede yan tümce olması gerekir CustomerId = a.Id? –

1

Bir pencere işlevi kullanabilirsiniz.

SELECT * 
    FROM (SELECT a.*, b.*, 
       ROW_NUMBER() OVER (PARTITION BY a.ID ORDER BY b.orderdate DESC, 
       b.ID DESC) rn 
      FROM customer a, ORDER b 
     WHERE a.ID = b.custid) 
WHERE rn = 1 

Her müşteri için (a.id) tüm siparişleri sıralar ve en sonuncu olanları hariç tutar. ORDER BY yan tümcesi, aynı tarihte birden fazla sipariş olması durumunda sipariş tarihini ve giriş kimliğini içerir.

Genel olarak, pencere işlevleri, çok sayıda kayıtta MAX() kullanılarak yapılan tüm aramalardan çok daha hızlıdır.

0

Bir Henüz yukarıda görmedim yaklaşım:

SELECT 
    C.*, 
    O1.ID 
FROM 
    dbo.Customers C 
INNER JOIN dbo.Orders O1 ON 
    O1.CustomerID = C.ID 
LEFT OUTER JOIN dbo.Orders O2 ON 
    O2.CustomerID = C.ID AND 
    O2.EntryTime > O1.EntryTime 
WHERE 
    O2.ID IS NULL 

Bu (yanı sıra inanıyorum diğer çözümleri) aynı müşteri için iki sipariş aynı giriş vakit varsayar. Eğer bir endişe varsa o zaman hangisinin "en son" olduğunu belirleyen bir seçim yapmanız gerekir. Bu bir endişe varsa, bir yorum gönderin ve bunu hesaba katmak gerekirse sorguyu genişletebilirim.

Sorgunun genel yaklaşımı, daha sonraki bir tarihle aynı müşteri için başka bir siparişin bulunmadığı bir müşterinin siparişini bulmaktır. Bu, tanım gereği en son sıradadır. Bu yaklaşım genellikle daha iyi bir performans, daha sonra türetilmiş tabloların veya alt sorguların kullanılmasını sağlar.

+0

Bu sorguyu test ettim ve şu ana kadarki diğer iki yanıt gibi çalışıyor. Aynı giriş süresiyle 2 siparişi nasıl ele alabileceğinizi ekleyebilir misiniz? – alextansc

+0

İlginç. Bir müşterinin her siparişe her siparişe katılmaya ihtiyaç duyacağından, bu her bir ekstra sipariş için katlanarak daha yavaş olmaz mı? –

0

Bu sorgu kabul edilen yanıt çok daha hızlıdır: Bu örnekteki

SELECT c.id as customer_id, 
    (SELECT co.id FROM customer_order co WHERE 
    co.customer_id=c.id 
    ORDER BY some_date_column DESC limit 1) as last_order_id 
    FROM customer c 
İlgili konular