Как получить максимальное число строк на группу / раздел в SQL Server? - PullRequest
13 голосов
/ 05 февраля 2011

Я использую 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

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

Ответы [ 6 ]

29 голосов
/ 05 февраля 2011

Попробуйте это:

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       
11 голосов
/ 05 февраля 2011

Сделайте то же самое снова.

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

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

3 голосов
/ 05 февраля 2011
; 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
1 голос
/ 29 августа 2018
SELECT * FROM (
        SELECT ROW_NUMBER() OVER(PARTITION BY OS.ContactId ORDER BY OS.Date ASC) AS FirstRow#,
        ROW_NUMBER() OVER(PARTITION BY OS.ContactId ORDER BY OS.Date DESC) AS LastRow#,
        OS.Contactid,CONVERT(VARCHAR,OS.Date,106) 'Purchase Month',
        OS.ProductId 'MyCII Subscription/Directory', OS.Charges 'Amount(INR)',OS.Date 'RAWDate'
        FROM tblOnlineServices OS
        WHERE Date IS NOT NULL AND Contactid IN('C000013112','C000010859') 
    ) FirstPurchase 
    WHERE FirstRow# = 1 OR LastRow# = 1
    ORDER BY Contactid, RAWDate
1 голос
/ 05 февраля 2011

менее крутой способ, я полагаю

; 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'
0 голосов
/ 05 февраля 2011

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...