t-sql选择两列之间的最大值,或者当col 2为null时为col 1

时间:2018-02-23 10:36:47

标签: tsql

这对我来说不容易在标题中描述(请原谅我),但这是我的问题:

假设您有下表:

CREATE TABLE Subscriptions (product char(3), start_date datetime, end_date datetime);

INSERT INTO @Subscriptions 
VALUES('ABC', '2015-01-28 00:00:00', '2016-02-15 00:00:00'),
    ('ABC', '2016-02-04 12:08:00', NULL),
    ('DEF', '2013-04-15 00:00:00', '2013-06-10 00:00:00'),
    ('GHI', '2013-01-11 00:00:00', '2013-04-08 00:00:00');

现在我想知道订阅有多长时间是主动的还是被动的。因此,我需要选择按产品分组的最新end_dates,但如果end_date为null,那么我想要start_date。

所以 - 我有:

product start_date          end_date
ABC     28-01-2015 00:00    15-02-2016 00:00
ABC     04-02-2016 12:08    NULL
DEF     15-04-2013 00:00    10-06-2013 00:00
GHI     11-01-2013 00:00    08-04-2013 00:00

我想在查询中找到的内容:

product relevant_date
ABC 04-02-2016 12:08
DEF 10-06-2013 00:00
GHI 08-04-2013 00:00

我尝试过使用union,这似乎有效,但它很慢,我的问题是:有没有更有效的方法来解决这个问题(我正在使用MS SQL Server 2012):

SELECT [product] 
    ,MAX([start_date]) AS start_date
    ,NULL AS [end_date]
    ,MAX([start_date]) AS relevant_date
FROM Subscriptions  
where end_date IS NULL
GROUP BY product

UNION 

SELECT [product] 
    ,NULL
    ,MAX([end_date])
    ,MAX([end_date])
FROM Subscriptions  
where end_date IS not NULL and product not in (SELECT product FROM Subscriptions  
where end_date IS NULL)
GROUP BY product

(如果您对我的问题有另一个标题的建议,我也全都耳朵!)

2 个答案:

答案 0 :(得分:0)

对于2012或更高版本,您可以使用distinctfirst_valueisnull的组合,如下所示:

SELECT  DISTINCT 
        product, 
        FIRST_VALUE(ISNULL(end_date,start_date)) 
            OVER(PARTITION BY product 
                 ORDER BY ISNULL(end_date, '9999-12-31') DESC) AS EndDate
FROM Subscriptions

结果:

product EndDate
ABC     04.02.2016 12:08:00
DEF     10.06.2013 00:00:00
GHI     08.04.2013 00:00:00

对于2008年和2012年之间的版本,您可以使用cterow_number来获得相同的效果:

;WITH CTE AS
(
    SELECT  product,
            ISNULL(end_date,start_date) As relevant_date,
            ROW_NUMBER() OVER(PARTITION BY product ORDER BY ISNULL(end_date, '9999-12-31') DESC) As rn
    FROM Subscriptions
)

SELECT  product, 
        relevant_date
FROM CTE
WHERE rn = 1

See a live demo on rextester.

答案 1 :(得分:0)

这应该这样做:

    select s1.product,MAX(case when useStartDate=1 then s1.startDate else s1.endDate end) 'SubscriptionDate'
    from @Subscriptions s1
    join (select s2s1.product, max(case when s2s1.endDate is null then 1 else 0 end) 'useStartDate' from @Subscriptions s2s1 group by s2s1.product) s2 on s1.product=s2.product
    group by s1.product