我正在尝试构造一个困难的SQL Server查询以选择特定数据。首先,让我给您一些背景信息...
我正在使用一个数据库,需要使用此查询访问3个表。您可以在图中看到该图。如您所见,此数据库中有用户。这些用户可以购买订阅,以在城市中使用一些公共自行车。订阅具有订阅类型。此订阅类型声明订阅有效的时间。可以是一天,一个月或一年。一个用户可以有多个订阅。
对于我的查询,我需要选择userId,名称,由街道,数字,邮政编码,城市和国家/地区代码组成的地址,以及订阅类型的描述。对于每个用户,我只需要最长的订阅时间。因此您必须在subscriptionTypeId DESC上过滤查询。不仅如此……一个用户可以拥有同一类型的多个订阅,因此我只需要最新的订阅即可。这意味着我还必须在订阅类型期间最长的时间上对ValidFrom DESC进行过滤。
我知道我需要为此使用子查询,但是似乎找不到合适的查询...这就是我所能走到的远,但是我一直在使用多种技术来尝试获得我所需要的:
SELECT
su.userId, u.name, u.street, u.number, u.zipcode, u.CountryCode, st.description,
MAX(su.validFrom) AS MaxValidFrom,
(SELECT MAX(SubscriptionTypeId) FROM dbo.Subscriptions
WHERE UserId = su.UserId) AS MaxSubscriptionTypeId
FROM
dbo.Users u
INNER JOIN
dbo.Subscriptions su ON u.userId = su.userId
INNER JOIN
dbo.SubscriptionTypes st ON su.subscriptionTypeId = st.subscriptionTypeId
HAVING
su.SubscriptionTypeId = MAX(su.SubscriptionTypeId)
ORDER BY
su.UserId, MaxValidFrom DESC;
预先感谢您的帮助!
Joren
Joren,
尝试像这样的缩放器功能调用
CREATE FUNCTION MaxSubscriptionTypeID
(@UserId int)返回int如开始宣告@ID int从dbo中选择@ID = MAX(SubscriptionTypeId)WHERE UserId = @UserID-返回函数结果返回idnull(@ ID,0)
END转到
选择su.userId,u.name,u.street,u.number,u.zipcode,u.CountryCode,st.description,MAX(su.validFrom)AS MaxValidFrom,dbo.MaxSubscriptionTypeID(su.UserId)AS MaxSubscriptionTypeId从dbo.Users u内部联接dbo.Subscriptions su ON u.userId = su.userId内部联接dbo.SubscriptionTypes st on su.subscriptionTypeId = st.subscriptionTypeId拥有su.SubscriptionTypeId = MAX(su.SubscriptionTypeId)订购su.UserId,MaxValidFrom DESC;
SQL可能会与内联子查询捆绑在一起,具体取决于功能和资源索引等。
我会避免使用自定义函数,因为查询计划几乎总是受到它的负面影响。
将其断开,将使您获得用户拥有的Max(SubscriptionTypeId),以及订阅该TypeId的用户的最新实例。
SELECT
u.userId, u.name, u.street, u.number, u.zipcode, u.CountryCode
--,st.description
--,MAX(su.validFrom) AS MaxValidFrom,
--,(SELECT MAX(SubscriptionTypeId) FROM dbo.Subscriptions WHERE UserId = su.UserId) AS MaxSubscriptionTypeId
into #temp
FROM
dbo.Users u
WHERE EXISTS (SELECT top 1 1 from dbo.Subscriptions i_su where i_su.UserId = u.UserId)
--Now you have a list of all who have at least 1 subscription inside a temp table.
Select u.*
,st.description
,su.ValidFrom
,su.SubscriptionTypeId
--This function will return a "Rank" for each user (partition) in order of the "Order By" clause.
,ROW_NUMBER() OVER (partition by u.UserId order by SubscriptionTypeId DESC, ValidFrom DESC) as RowNo
into #temp2
FROM #temp u
INNER JOIN dbo.Subscriptions su
ON u.userId = su.userId
INNER JOIN dbo.SubscriptionTypes st
ON su.subscriptionTypeId = st.subscriptionTypeId
SELECT *
FROM #temp2
where RowNo = 1
-- RowNo 1 has the data you want based on the rank.
if (object_id('temptb..#temp') IS NOT NULL)
DROP TABLE #temp
if (object_id('temptb..#temp2') IS NOT NULL)
DROP TABLE #temp2