2013-05-10 2 views
2

Я поручено следующее:SQL Server - Получить клиентов с п-го порядка в диапазоне конкретных дат

  • Выберите список всех клиентов, которые имели их п-го порядка в течение определенного диапазона дат (как правило, конкретный месяц).
  • Этот список должен содержать: идентификатор клиента, сумма первых п порядков

Мои таблицы что-то вроде этого:

  • [dbo.customers]: CUSTOMERID
  • [ДБО .]: orderID, customerID, orderDate, orderTotal

Вот что я пытался до сих пор:

-- Let's assume our threshold (n) is 10 
-- Let's assume our date range is April 2013 
-- Get customers that already had n orders before the beginning of the given date range. 
DECLARE @tmpcustomers TABLE (tmpcustomerID varchar(8)) 
INSERT INTO 
    @tmpcustomers 
SELECT 
    c.customerID 
FROM 
    orders o 
    INNER JOIN customers c ON o.customerID = c.customerID 
WHERE 
    o.orderDate < '2013-04-01' 
GROUP BY c.customerID 
HAVING (COUNT(o.orderID) >= 10) 


-- Now get all customers that have n orders sometime within the given date range 
-- but did not have n orders before the beginning of the given date range. 
SELECT 
    a.customerID, SUM(orderTotal) AS firstTenOrderTotal 
SELECT 
    o.customerID, o.orderID, o.orderTotal 
FROM 
    orders o 
    INNER JOIN customers c ON c.customerID = o.customerID  
WHERE 
    a.customerID NOT IN (SELECT tmpcustomerID FROM @tmpcustomers) 
AND 
    o.orderDate > '2013-04-01' 
AND 
    o.orderDate < '2013-05-01' 
GROUP BY c.customerID 
    HAVING COUNT(o.orderID) >= 10 

Это похоже на работу, но это неуклюжее и медленно. Еще одна большая проблема заключается в том, что firstTenOrderTotal на самом деле является SUM от общего количества заказов к концу данного диапазона дат и не обязательно в первую очередь. 10.

Любые предложения для лучшего подхода были бы высоко оценены.

ответ

0
  1. Вставьте в @tmpcustomers, почему вы присоединяетесь к таблице клиентов? В таблице заказов уже есть идентификатор клиента, который вы хотите. Кроме того, почему вы ищете заказы, где дата заказа до вашего диапазона дат? Разве вы не хотите, чтобы клиенты имели более чем n заказов между диапазоном дат? Это упростит второй запрос.

  2. Только имея клиентов с n или более заказами в переменной таблицы @tmpcustomers, вы должны просто иметь возможность присоединиться к ней и таблицу заказов во втором запросе, чтобы получить сумму всех заказов для тех клиентов, где вы в очередной раз ограничиваете записи таблиц заказов своим диапазоном дат (чтобы вы не получали заказы за пределами этого диапазона). Это приведет к удалению оператора having и соединения в таблицу Customers в вашем окончательном запросе результата.

+0

Спасибо за ответ. – sqlhurtsmyheadsometimes

+0

Спасибо за ответ. 1) Хорошая точка. Я могу удалить соединение из вставки в @tmpcustomers. Я ищу заказы, где дата до диапазона дат, потому что я в основном выбираю список идентификаторов для исключения во втором запросе. Я получаю список людей, у которых уже было 10 или более заказов до начала диапазона дат, а затем исключая их из моего следующего запроса. Теперь, когда я действительно объясняю, что происходит, я думаю, что я слишком много думал об этой части, и это может быть ненужным. – sqlhurtsmyheadsometimes

+0

Чтобы прояснить мое намерение - я хочу выбрать всех клиентов, которые достигли своего общего порядка в пределах указанного диапазона. Мне также нужна сумма этих первых n порядковых сумм. – sqlhurtsmyheadsometimes

0

Дайте это попробовать. В зависимости от вашего распределения заказов он может работать лучше. В этом запросе я собираю список заказов в диапазоне, а затем оглядываясь назад, чтобы подсчитать количество предшествующих заказов (также захватив orderTotal).

примечание: я принимаю приращение orderID при размещении заказов. Если это не так, просто используйте row_number над датой для проецирования последовательности в запрос.

declare @orders table (orderID int primary key identity(1,1), customerID int, orderDate datetime, orderTotal int) 
insert into @orders (customerID, orderDate, orderTotal) 
    select 1, '2013-01-01', 1 union all 
    select 1, '2013-01-02', 2 union all 
    select 1, '2013-02-01', 3 union all 
    select 2, '2013-01-25', 5 union all 
    select 2, '2013-01-26', 5 union all 
    select 2, '2013-02-02', 10 union all 
    select 2, '2013-02-02', 10 union all 
    select 2, '2013-02-04', 20 

declare @N int, @StartDate datetime, @EndDate datetime 
select @N = 3, 
     @StartDate = '2013-02-01', 
     @EndDate = '2013-02-20' 

select o.customerID, 
     [total] = o.orderTotal + p.total --the nth order + total prior 
from @orders o 
cross 
apply ( select count(*)+1, sum(orderTotal) 
      from @orders 
      where customerId = o.customerID and 
        orderID < o.orderID and 
        orderDate <= o.orderDate 
     ) p(n, total) 
where orderDate between @StartDate and @EndDate and p.n = @N 
0

Вот мое предложение:

Use Northwind 
GO 


select ords.OrderID , ords.OrderDate , '<-->' as Sep1 , derived1.* from 
dbo.Orders ords 
join 
(
select CustomerID, OrderID, ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY OrderId DESC) AS ThisCustomerCardinalOrderNumber from dbo.Orders 
) as derived1 
    on ords.OrderID = derived1.OrderID 

where 
derived1.ThisCustomerCardinalOrderNumber = 3 
and ords.OrderDate between '06/01/1997' and '07/01/1997' 

EDIT :::::::::

Я взял пример КТР и переработан его для нескольких клиентов (видно ниже). Дайте ему попробовать колледж.

Use Northwind 
GO 



declare @BeginDate datetime 
declare @EndDate datetime 

select @BeginDate = '01/01/1900' 
select @EndDate = '12/31/2010' 

; 
WITH 
MyCTE /* http://technet.microsoft.com/en-us/library/ms175972.aspx */ 
(ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address], 
City,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName, 
ProductID,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight,ROWID) AS 
(
SELECT 
ShipName ,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address] 
,City ,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName 
,ProductID ,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight 
, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate , ProductName ASC) as ROWID /* Note that the ORDER BY (here) is directly related to the ORDER BY (near the very end of the query) */ 
FROM 
dbo.Invoices inv /* “Invoices” is a VIEW, FYI */ 
where 
(inv.OrderDate between @BeginDate and @EndDate) 
) 
SELECT 
/* 
ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address], 
City,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName, 
ProductID,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight, 
*/ 

/*trim the list down a little for the final output */ 

CustomerID ,OrderID , OrderDate, (ExtendedPrice + Freight) as ComputedTotal 

/*The below line is the “trick”. I reference the above CTE, but only get data that is less than or equal to the row that I am on (outerAlias.ROWID)*/ 
, (Select SUM (ExtendedPrice + Freight) from MyCTE innerAlias where innerAlias.ROWID <= outerAlias.ROWID and innerAlias.CustomerID = outerAlias.CustomerID) as RunningTotal 
, ROWID as ROWID_SHOWN_FOR_KICKS , OrderDate as OrderDate 
FROM 
MyCTE outerAlias 

GROUP BY CustomerID ,OrderID, OrderDate, ProductName,(ExtendedPrice + Freight) ,ROWID,OrderDate 

/*Two Order By Options*/ 
ORDER BY outerAlias.CustomerID , outerAlias.OrderDate , ProductName 

/* << Whatever the ORDER BY is here, should match the “ROW_NUMBER() OVER (ORDER BY ________ ASC)” statement inside the CTE */ 
/*ORDER BY outerAlias.ROWID */ /* << Or, to keep is more “trim”, ORDER BY the ROWID, which will of course be the same as the “ROW_NUMBER() OVER (ORDER BY” inside the CTE */ 
+0

Спасибо. Я пытаюсь это сделать сейчас. Проблема, с которой я столкнулся до сих пор, заключается в том, что заказы в моей ситуации на самом деле представляют собой представление. Я получаю сообщение об ошибке, пытаясь использовать его в вашем примере. Я буду продолжать общаться с ним и отчитываться. – sqlhurtsmyheadsometimes

+0

Ну, теперь я вижу «СУМ», которого я не делал. Я даю ссылку здесь ... на текущем общем CTE, который я сделал однажды. Оставайтесь на линии. – granadaCoder

+0

Спасибо! Я проверю это и дам вам знать ... – sqlhurtsmyheadsometimes

 Смежные вопросы

  • Нет связанных вопросов^_^