Как получить максимальный номер строки на группу/раздел в SQL Server?

Я использую SQL Server 2005. У меня есть таблица платежей с идентификаторами платежа, идентификаторами пользователя и отметками времени. Я хочу найти самую последнюю оплату для каждого пользователя. Это легко найти и найти ответ. Однако я также хочу знать, является ли последний платеж первым платежом пользователя или нет.

У меня есть следующее, которое будет указывать каждый пользовательский платеж:

SELECT
    p.payment_id,
    p.user_id,
    ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber
FROM
    payment p

Я не делаю умственного прыжка, который затем позволяет мне выбрать самый высокий номер платежа для каждого пользователя. Если я использую вышеуказанное как подзапрос, используя MAX (номер платежа), а затем группируя по user_id, я теряю нужный мне payment_id. Но если я также добавлю payment_id в предложение group by, я вернусь к одной строке за платеж. Я уверен, что я упускаю из виду очевидное. Любая помощь?

Ответ 1

Попробуйте следующее:

SELECT a.*, CASE WHEN totalPayments>1 THEN 'NO' ELSE 'YES' END IsFirstPayment
  FROM(
                SELECT  p.payment_id,     
                                p.user_id,     
                                ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date DESC) AS paymentNumber,
                                SUM(1) OVER (PARTITION BY p.user_id) AS totalPayments
                    FROM payment p 
            ) a
WHERE   paymentNumber = 1       

Ответ 2

Повторите то же самое.

SELECT
    p.payment_id,
    p.user_id,
    ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber,
    ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date DESC) AS reversePaymentNumber,
FROM
    payment p

Теперь последний платеж имеет номер обратного платежа 1, а количество платежей будет равно количеству платежей.

Ответ 3

; with cte as (
SELECT
    p.payment_id,
    p.user_id,
    ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date desc) AS paymentNumber
FROM
    payment p
) select * from cte where paymentNumber = 1

Ответ 4

Как насчет этого?

SELECT
    p.user_id,
    MAX(p.payment_date) as lastPayment,
    CASE COUNT(p.payment_id) WHEN 1 THEN 1 ELSE 0 END as isFirstPayment
FROM
    payment p
GROUP BY
    p.user_id

Ответ 5

менее холодный способ, я полагаю,

; with maxp as
(
    select
        p.user_id,
        max(p.payment_date) as MaxPaymentDate
    from payment p
    group by p.userid
),
nump as
(
    select
        p.payment_id,     
        p.user_id,     
        p.payment_date,
        ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber 
    FROM payment p
),
a as
(
select
    nump.payment_id,
    nump.user_id,
    nump.paymentNumber
    case when maxp.MaxPaymentDate is null then 'Old' else 'New' end as NewState
from nump
    left outer join maxp
        on nump.user_id=maxp.user_id
            and nump.payment_date=maxp.MaxPaymentDate
)

select
*
from a
where NewState='New'