Mat*_*att 30 t-sql sql-server-2005 aggregate-functions
我有2个表 - 一个Account表和一个Users表.每个帐户可以有多个用户.我有一个场景,我想对这两个表执行单个查询/连接,但我想要所有的帐户数据(帐户.*)和只有第一组用户数据(特别是他们的名字).
我没有在我的聚合小组上做"最小"或"最大",而是想做一个"第一次".但是,显然,TSQL中没有"First"聚合函数.
有关如何获取此查询的任何建议?显然,很容易获得Account x Users的笛卡尔积:
SELECT User.Name, Account.* FROM Account, User
WHERE Account.ID = User.Account_ID
Run Code Online (Sandbox Code Playgroud)
但是我怎样才能根据User.ID的顺序从产品中获取第一个用户?
Ada*_*son 25
而不是分组,像这样去做...
select
*
from account a
join (
select
account_id,
row_number() over (order by account_id, id) -
rank() over (order by account_id) as row_num from user
) first on first.account_id = a.id and first.row_num = 0
Run Code Online (Sandbox Code Playgroud)
我知道我的答案有点晚了,但这可能对其他人有所帮助.有一种方法可以在SQL Server中实现First()和Last(),这里是:
Stuff(Min(Convert(Varchar, DATE_FIELD, 126) + Convert(Varchar, DESIRED_FIELD)), 1, 23, '')
Run Code Online (Sandbox Code Playgroud)
对First()使用Min(),对Last()使用Max().DATE_FIELD应该是确定它是第一个还是最后一个记录的日期.DESIRED_FIELD是您想要第一个或最后一个值的字段.它的作用是:
干得好!
编辑:我遇到第一个公式的问题:当DATE_FIELD以.000为毫秒时,SQL Server将日期作为字符串返回NO毫秒,从而删除DESIRED_FIELD中的前4个字符.我只是将格式更改为"20"(没有毫秒)并且它的工作非常好.唯一的缺点是如果你有两个在同一秒创建的字段,那么排序可能会很混乱......在cas中你可以恢复为"126"格式.
Stuff(Max(Convert(Varchar, DATE_FIELD, 20) + Convert(Varchar, DESIRED_FIELD)), 1, 19, '')
Run Code Online (Sandbox Code Playgroud)
编辑2:我最初的意图是返回最后一个(或第一个)NON NULL行.我被问到如何返回最后一行或第一行,无论是否为null.只需将一个ISNULL添加到DESIRED_FIELD即可.当您使用+运算符连接两个字符串时,如果其中一个为NULL,则结果为NULL.所以使用以下内容:
Stuff(Max(Convert(Varchar, DATE_FIELD, 20) + IsNull(Convert(Varchar, DESIRED_FIELD), '')), 1, 19, '')
Run Code Online (Sandbox Code Playgroud)
Select *
From Accounts a
Left Join (
Select u.*,
row_number() over (Partition By u.AccountKey Order By u.UserKey) as Ranking
From Users u
) as UsersRanked
on UsersRanked.AccountKey = a.AccountKey and UsersRanked.Ranking = 1
Run Code Online (Sandbox Code Playgroud)
这可以通过使用Partition By子句来简化.在上面,如果一个帐户有三个用户,那么子查询将它们编号为1,2和3,对于不同的AccountKey,它将重置numnbering.这意味着对于每个唯一的AccountKey,总会有1,可能是2,3,4等.
因此,您在Ranking = 1上过滤以从每个组中获取第一个.
这将为每个帐户提供一行,如果该帐户至少有一个用户,那么它将为您提供最低密钥的用户(因为我使用左连接,即使没有,您也将始终获得帐户列表用户存在).Order By u.UserKey如果您希望按字母顺序或其他标准选择第一个用户,请替换为其他字段.
我已经对所有方法进行了基准测试,实现这一点的最简单、最快的方法是使用外部/交叉应用
SELECT u.Name, Account.* FROM Account
OUTER APPLY (SELECT TOP 1 * FROM User WHERE Account.ID = Account_ID ) as u
Run Code Online (Sandbox Code Playgroud)
CROSS APPLY 的工作方式与 INNER JOIN 类似,并获取两个表相关的行,而 OUTER APPLY 的工作方式与 LEFT OUTER JOIN 类似,并从左表中获取所有行(Account here)