Получить первое поле, когда количество достигает значения - PullRequest
3 голосов
/ 14 апреля 2011

Мне нужно сегментировать клиентов по первой дате, когда их количество заказов достигло определенного значения.

Например, у нас есть таблица заказов

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

(причина: 01.03.2011, клиент достиг 3 заказов)

Как я могу это сделать?

Спасибо

Обновление:

Я смотрю на ваши решения (большое спасибо!), Но мне нужно сделать то же самое и с SUM (скажем, в таблице выше естьполе под названием сумма, и я хотел бы сегментировать клиентов и получить первую дату, когда клиентские заказы достигли 100 долларов СШАнемного потеряно здесь .. есть идеи?

Ответы [ 4 ]

1 голос
/ 14 апреля 2011

Я бы сделал что-то вроде этого:

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

Вы можете указать идентификатор клиента и количество строк для обработки в качестве параметров для любой процедуры, которую вы в конечном итоге используете.

0 голосов
/ 14 апреля 2011

Тестовая таблица и тестовые данные

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
0 голосов
/ 14 апреля 2011

При этом будут выбраны все клиенты с 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

Для выбора одного клиента с датой 3-го заказа, который можно изменить с дополнительным условием для этого.

AND a.ClientID = @clientID

ОБНОВЛЕНИЕ на основе обновления вопроса - этот запрос с небольшими изменениями по сравнению с подсчетом голосов дает выбор текущей суммы. Здесь перечислено еще несколько техник для бегущей суммы .

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 голосов
/ 14 апреля 2011

Примерно так:

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

Редактировать Мое решение не может быть расширено, чтобы покрыть требование sum () из-за неполной поддержки оконных функций в 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...