2011-04-14 66 views
3

我需要按客户的订单计数达到特定值的第一个日期来对客户进行细分。当计数达到一个值时获取第一个字段

例如,我们有订单

ID, ClientID, Date 

1, 1, 1/1/2011 
2, 1 2/1/2011 
3, 1 3/1/2011 
4, 1 4/1/2011 

的表,我想获得所有谁拥有至少3下订单的客户,并获得日期字段,当他们到达3个数量级。 在我的例子中,查询将显示:

ClientID: 1, Date: 3/1/2011 

(在2011/3/1原因,客户已达3级)

我该怎么办呢?

感谢

更新:

我看您的解决方案(!非常感谢你),但我需要做同样的事情也与SUM(可以说上表中有一个叫场金额和我想细分客户,并获得客户订单达到100美元的第一个日期) 我虽然这种解决方案将帮助我理解逻辑,并轻松地将计数转换为总和并作出新的查询,但我得到了一点点有点在这里丢失..任何想法?

回答

0

这将选择所有客户与3订单与3日的日期。

--DECLARE @clientID INT 
--SET @clientID = 1 
DECLARE @count INT 
SET @count = 3  -- Set the count to this variable. 

SELECT ClientID, [Date] 
FROM [yourtable] a 
WHERE COALESCE( (SELECT COUNT(*) 
         FROM [yourtable] b 
         WHERE b.[Date] < a.[Date] and b.ClientID = a.ClientID),0) = @count - 1 
ORDER BY ClientID 

要选择第三个订单日期的单个客户,可以用附加条件对其进行修改。基于问题的更新

AND a.ClientID = @clientID 

UPDATE - 此查询与计数稍加修改woud给你运行总和选择。这里列出的其他技术仅为running sum

DECLARE @sum INT 
SET @count = 100  -- Set the amount to this variable. 

SELECT ClientID, [Date] 
FROM [yourtable] a 
WHERE (a.Amount + COALESCE( (SELECT SUM(b.Amount) 
         FROM [yourtable] b 
         WHERE b.[Date] < a.[Date] and b.ClientID = a.ClientID),0)) = @sum 
ORDER BY ClientID 
+0

这正是我所做的。尽管这个解决方案可能或可能不是像我第一次提到的那样最好的方法,但这对我的两个问题都是最好的解决方案 – Shay 2011-04-14 12:57:02

0

事情是这样的:

SELECT clientid, date 
FROM (
    SELECT id, 
      clientid, 
      row_number() over (partition by clientid order by date) as running_count, 
      date 
    FROM orders 
) t 
WHERE running_count = 3 

编辑
我的解决方案不能扩展到覆盖的总和()的要求,由于在SQL Server窗口函数的不完全的支持。

但对于完整性,我包括这仍然是一个例子:

SELECT clientid, date 
FROM (
    SELECT id, 
      clientid, 
      row_number() over (partition by clientid order by date) as running_count, 
      sum(amount) over (partition by clientid order by date) as running_sum, 
      date 
    FROM orders 
) t 
WHERE running_sum = 100 
    OR running_count = 3 

但再次:这将在SQL Server不工作

1

我会沿着这行做一些事情:

DECLARE @ClientId int, @RowNumber int 
SELECT @ClientId = 1, @RowNumber = 3 

SELECT ClientId, [Date] 
FROM 
(
    SELECT TOP (@RowNumber) ClientId, [Date], ROW_NUMBER() OVER(ORDER BY ID) AS RowNumber 
    FROM Test 
    WHERE ClientId = @ClientId 
) D 
WHERE RowNumber = @RowNumber 

您可以将客户端ID和行数作为参数处理,以处理最终使用的任何过程。

+0

是否有可能使用此查询,但总计字段,而不是计数? – Shay 2011-04-14 09:43:19

+0

听起来像门柱在这里移动了一些:) – 2011-04-14 09:51:53

+0

现在问你的问题是你正在寻找一个正在运行的总数,并且据我所知你不能在SQL服务器 – 2011-04-14 09:55:54

0

测试表和测试数据

declare @T table (ID int, ClientID int, [Date] datetime, Amount money) 

insert into @T values 
(1, 1, '1/1/2011', 10), 
(2, 1, '2/1/2011', 20), 
(3, 1, '3/1/2011', 30), 
(4, 1, '4/1/2011', 40), 
(5, 2, '1/1/2011', 10), 
(6, 2, '2/1/2011', 20), 
(7, 2, '3/1/2011', 30) 

获得第三排也不是那么难。这与a_horse_with_no_name提供的解决方案相同。

declare @Row int = 3 

;with cte as 
(
    select *, 
    row_number() over(partition by ClientID order by [Date]) as rn 
    from @T 
) 
select * 
from cte 
where rn = @Row 

要运行总和超过一个值,要获得行是有点困难。这是一个使用临时表来更新运行总和的循环版本。

declare @sum money = 30 

select *, cast(0 as money) as Running 
into #T 
from @T 

declare @rn int = 1 

;with cte as 
(
    select 
    Running, 
    Amount, 
    row_number() over(partition by ClientID order by [Date]) as rn 
    from #T 
) 
update cte set 
    Running = Amount 
where 
    rn = @rn 

while @@rowcount >= 1 
begin 
    set @rn = @rn + 1 

    ;with cte as 
    (
    select 
     Running, 
     Amount, 
     row_number() over(partition by ClientID order by [Date]) as rn 
    from #T 
) 
    update cte set 
    Running = Running + Amount 
    where rn = @rn 
end 

;with cte as 
(
    select *, 
    row_number() over(partition by ClientID order by [Date]) as rn 
    from #T 
    where Running >= @sum 
) 
select * 
from cte 
where rn = 1 

drop table #T 
相关问题