2011-02-10 26 views
5

Tôi cần lời khuyên từ các chuyên gia SQL nâng cao hơn về điều này.Cách tìm Khách hàng đã mua Sản phẩm A và D> cách nhau 6 tháng?

Tôi đang được yêu cầu tạo báo cáo cho thấy khách hàng đã mua sản phẩm 105 và , sau đó họ đã mua sản phẩm 312 hơn 6 tháng sau.

Ví dụ, tôi có đơn đặt hàng bảng sau:

RecID CustID ProdID InvoiceDate 
    1  20  105  01-01-2009 
    2  20  312  01-04-2009 
    3  20  300  04-20-2009 
    4  31  105  07-10-2005 
    5  45  105  10-03-2007 
    6  45  300  11-10-2007 
    7  45  312  08-25-2008 

Tôi cần một báo cáo rằng nhìn vào bảng này và trở lại với:

CustID ElapsedDays 
    45  327 

Tôi có cần phải sử dụng một con trỏ và lặp lại hồ sơ theo hồ sơ, so sánh ngày tháng khi tôi đi?

Nếu có, quy trình con trỏ sẽ như thế nào? Tôi đã không làm việc với con trỏ, mặc dù tôi đã làm nhiều năm lập trình thủ tục.

Cảm ơn!

Trả lời

1
select A.CustID, ElapsedDays = datediff(d, A.InvoiceDate, B.InvoiceDate) 
from Orders A 
inner join Orders B on B.CustID = A.CustID 
    and B.ProdID = 312 
    -- more than 6 months ago 
    and B.InvoiceDate > dateadd(m,6,A.InvoiceDate) 
where A.ProdID = 105 

Truy vấn trên là một sự giải thích đơn giản về yêu cầu của bạn, nơi mà bất kỳ mua của A (105) và D (312) xảy ra 6 tháng ngoài. Nếu khách hàng mua

  • Một tháng một,
  • Một tháng ba,
  • A trong tháng bảy, và sau đó mua
  • D vào tháng

nó sẽ quay trở lại 2 hàng cho khách hàng (tháng 1 và tháng 3), kể từ khi cả hai người được theo dõi bởi một D mua hơn 6 tháng sau đó.

Truy vấn sau thay vào đó tìm tất cả các trường hợp mua LAST A từ 6 tháng trở lên trước khi mua lần đầu tiên.

select A.CustID, ElapsedDays = datediff(d, A.InvoiceDate, B.InvoiceDate) 
from (
    select CustID, Max(InvoiceDate) InvoiceDate 
    from Orders 
    where ProdID = 105 
    group by CustID) A 
inner join (
    select CustID, Min(InvoiceDate) InvoiceDate 
    from Orders 
    where ProdID = 312 
    group by CustID) B on B.CustID = A.CustID 
    -- more than 6 months ago 
    and B.InvoiceDate > dateadd(m,6,A.InvoiceDate) 

Và nếu cho cùng một kịch bản trên, bạn không muốn gặp lại khách hàng này vì A (tháng bảy) và D (Sep) mua hàng không 6 tháng ngoài, bạn có thể loại trừ chúng khỏi truy vấn đầu tiên sử dụng bộ lọc EXISTS.

select A.CustID, ElapsedDays = datediff(d, A.InvoiceDate, B.InvoiceDate) 
from Orders A 
inner join Orders B on B.CustID = A.CustID 
    and B.ProdID = 312 
    -- more than 6 months ago 
    and B.InvoiceDate > dateadd(m,6,A.InvoiceDate) 
where A.ProdID = 105 
    AND NOT EXISTS (
    SELECT * 
    FROM Orders C 
    WHERE C.CustID=A.CustID 
    AND C.InvoiceDate > A.InvoiceDate 
    and C.InvoiceDate < B.InvoiceDate 
    and C.ProdID in (105,312)) 
+0

Cảm ơn cyberkiwi. Thật là một câu trả lời chu đáo, toàn diện! Tôi đánh giá cao nó. Tôi sẽ nghiên cứu điều này. – BornInChicago

0

Có lẽ một cái gì đó như thế này sẽ làm việc:

select CustID, datediff(day, O1.InvoiceDate, O2.InvoiceDate) as ElapsedDays 
from Orders O1 
    inner join Orders O2 
     on O1.CustId = O2.CustId 
     and dateadd(month, 6, O1.InvoiceDate) <= O2.InvoiceDate 
where 
    O1.ProdId = 105 
    and O2.ProdId = 312 
+0

Andy, Cảm ơn. Nhưng điều này mang lại cho tôi: Tên cột mơ hồ 'CustID'. – BornInChicago

1

Bạn có thể làm điều này với một sự tự tham gia:

select a.custid, DATEDIFF(dd, a.invoicedate, b.invoicedate) 
from #t a 
inner join #t b 
    on a.custid = b.custid 
     and a.prodid = 105 
     and b.prodid = 312 
where DATEDIFF(dd, a.invoicedate, b.invoicedate) > 180 

Việc sử dụng đầu tiên của #t (aliased a) là dành cho những sản phẩm đầu tiên và việc sử dụng thứ hai của #t (aliased b) dành cho sản phẩm thứ hai. Đây là tập lệnh tôi đã sử dụng để kiểm tra:

create table #t (
    recid int, 
    custid int, 
    prodid int, 
    invoicedate date) 

insert into #t select 1, 20, 105, '1/1/2009' 
insert into #t select 2, 20, 312,'1/4/2009' 
insert into #t select 3, 20, 300,'4/20/2009' 
insert into #t select 4, 31, 105,'7/10/2005' 
insert into #t select 5, 45, 105,'10/3/2007' 
insert into #t select 6, 45, 300,'11/10/2007' 
insert into #t select 7, 45, 312,'8/25/2008' 

select a.custid, DATEDIFF(dd, a.invoicedate, b.invoicedate) 
from #t a 
join #t b 
    on a.custid = b.custid 
     and a.prodid = 105 
     and b.prodid = 312 
where DATEDIFF(dd, a.invoicedate, b.invoicedate) > 180 

drop table #t 
+0

Cảm ơn Paul. Điều đó hoạt động. – BornInChicago

2

Bạn có một số câu trả lời hay ở trên; tự tham gia là con đường để đi. Tôi muốn gợi ý cho bạn cách tốt nhất để suy nghĩ về một vấn đề như thế này. Điều gì sẽ xảy ra nếu bạn đã mua Sản phẩm A và D trong các bảng khác nhau? Không phải là bạn nên lưu trữ dữ liệu theo cách đó, nhưng bạn nên suy nghĩ về dữ liệu theo cách đó.Nếu bạn đã làm, bạn có thể tham gia, ví dụ: product_a_purchases vào product_d_purchases trên ID khách hàng và so sánh ngày. Vì vậy, cho các mục đích truy vấn của bạn, đó là những gì bạn cần để sản xuất. Không phải bảng thực sự trên đĩa là product_a_purchases, nhưng là một bảng các bản ghi từ bảng mua hàng của bạn chỉ bao gồm các giao dịch mua sản phẩm A và giống với Sản phẩm D. Đó là nơi tự tham gia.

+0

Carl, Cảm ơn. Điều này thực sự giúp tôi hiểu được "lý do" đằng sau "cái gì". Tôi đánh giá cao việc bạn dành thời gian đưa ra nhận xét sâu sắc hơn này để giúp tôi. – BornInChicago

Các vấn đề liên quan