我有一张桌子,上面是这样的:
User | ProfileId | OpenDate | CloseDate | ProfileValue
----------------------------------------------------------------------------
test | 1 | 2018-10-25 11:40:00 | 2018-10-25 11:40:00 | 10
test | 3 | 2018-10-25 11:40:00 | NULL | 3
test | 4 | 2018-10-25 11:45:00 | 2018-10-25 11:40:00 | 4
test | 7 | 2018-10-18 10:00:00 | NULL | 5
一个打开的帐户是一个关闭日期为空的帐户。我想要检索最近打开的帐户(即MAX(OpenDate)
,其中CloseDate IS NULL
)的ProfileId,并且我想要这些已打开帐户的最大ProfileValue。在上面的示例中,这意味着我想返回包含ProfileId 3和ProfileValue 5的行。因此理想情况下:
User | ProfileId | ProfileValue
--------------------------------
test | 3 | 5
但是,我遇到的麻烦是没有打开的帐户时,我想返回最近打开的帐户(无论关闭时间如何)以及最大ProfileValue是多少,并且我不确定该如何处理。
对于我的示例,到目前为止,我所拥有的查询如下所示:
SELECT U.User,
MAX(P.OpenDate) AS OpenDate,
CASE WHEN MAX(CASE WHEN P.CloseDate IS NULL THEN 1 ELSE 0 END) = 0
THEN MAX(P.CloseDate) END AS CloseDate, -- use null CloseDate field if available
MAX(R.ProfileValue) AS ProfileValue
FROM #UserIds U
LEFT JOIN dbo.Profiles P
ON U.User = P.User
INNER JOIN [dbo].[ReferenceTable] R
ON P.ProfileId = R.ProfileId
GROUP BY U.User, P.CloseDate
HAVING P.CloseDate IS NULL -- TO DO?
这将返回
User | OpenDate | CloseDate | ProfileValue
----------------------------------------------------------------
test | 2018-10-25 11:40:00 | NULL | 5
然后我可以将此表重新连接到Profiles表以获取ProfileId,尽管这也不是特别有效。
在没有未结帐户的情况下,如何解决我的HAVING
子句以包括方案?我试图做类似
HAVING ISNULL(P.CloseDate, '2079-06-06 23:59:00') = MAX(COALESCE(P.CloseDate, '2079-06-06 23:59:00'))
尝试将NULL
的CloseDate视为最大值,但这将返回太多行。还有没有更好的方法可以在查询中返回ProfileId,这样我就不必再次将结果表联接到自身了?
编辑:
适应@Gordon Linoff的答案:
SELECT A.User, A.ProfileId, A.OpenDate, A.CloseDate, A.ProfileValue
FROM #UserIds U OUTER APPLY
(SELECT TOP 5 P.User, P.ProfileId, P.OpenDate, P.CloseDate, R.ProfileValue
FROM dbo.Profiles P
INNER JOIN [dbo].[ReferenceTable] R
ON P.ProfileId = R.ProfileId
WHERE U.User = P.User
ORDER BY (CASE WHEN p.CloseDate IS NULL THEN 1 ELSE 2 END), -- put open accounts first
P.OpenDate DESC -- put most recent opened first
) A
这将返回:
User | ProfileId | OpenDate | CloseDate | ProfileValue
----------------------------------------------------------------------------
test | 3 | 2018-10-25 11:40:00 | NULL | 3
test | 7 | 2018-10-18 10:00:00 | NULL | 5
test | 4 | 2018-10-25 11:45:00 | 2018-10-25 11:40:00 | 4
test | 1 | 2018-10-25 11:40:00 | 2018-10-25 11:40:00 | 10
因此,如果我修改子查询以返回TOP 1
,它将提供正确的ProfileId,但是在这种情况下,我还需要获取未结帐户的MAX(ProfileValue)
(为5)。没有开设的帐户,只需返回所有帐户的最大值即可。我正在尝试各种group by子句,但它们似乎会乱序ProfileId顺序。我的备份计划是仅在单独的查询中检索最大ProfileValue,但这效率低下。关于如何解决此查询的任何想法?
答案 0 :(得分:1)
使用横向联接似乎是一个好情况:
SELECT p.*
FROM #UserIds U OUTER APPLY
(SELECT p.*
FROM dbo.Profiles P
WHERE U.User = P.User
ORDER BY (CASE WHEN p.CloseDate IS NULL THEN 1 ELSE 2 END), -- put open accounts first
o.OpenDate DESC -- put most recent opened first
) p;
您的查询提到其他表。我不明白它们的用途,因为它们不是问题的一部分。
答案 1 :(得分:0)
我改编自戈登·利诺夫(Gordon Linoff)的回答。我使用他的建议来获取最近打开的ProfileId,并使用我的旧想法来获取ProfileValue,然后将两个表连接在一起。这可能不是执行此操作的最佳方法,但是我已经对其进行了测试,并且似乎可以正常工作。
SELECT D.User, D.ProfileId, D.ProfileValue
FROM
(
SELECT C.*, CASE WHEN (ROW_NUMBER() OVER
(PARTITION BY User ORDER BY User))=1 THEN 1 ELSE 0 END FirstTime -- We only want the first time the User appears in the result set
FROM
(
SELECT A.User, A.ProfileId, B.ProfileValue
FROM #Users U OUTER APPLY
(SELECT TOP 1 P.User, P.ProfileId, P.OpenDate, P.CloseDate, L.ProfileValue
FROM [dbo].[Profiles] P
INNER JOIN [dbo].[ReferenceTable] L
ON P.ProfileId = L.ProfileId
WHERE U.User = P.User
ORDER BY (CASE WHEN p.CloseDate IS NULL THEN 1 ELSE 2 END), -- put open accounts first
P.OpenDate DESC -- put most recent opened first
) A
LEFT OUTER JOIN
(SELECT U.User,
MAX(P.OpenDate) AS OpenDate,
CASE WHEN MAX(CASE WHEN P.CloseDate IS NULL THEN 1 ELSE 0 END) = 0
THEN MAX(P.CloseDate) END AS CloseDate, -- use null CloseDate field if available
MAX(L.ProfileValue) AS ProfileValue
FROM #Users U
LEFT JOIN [dbo].[Profiles] P
ON U.User = P.User
INNER JOIN [dbo].[ReferenceTable] L
ON P.ProfileId = L.ProfileId
GROUP BY U.User, P.CloseDate
) B
ON A.User = B.User
AND A.OpenDate = B.OpenDate
) C
) D
WHERE D.FirstTime = 1