在SQL Server 2012中使用Top
我有一个表联系人,父表到表活动。我想为每个联系人选择最新的活动,但要获得多行 这是我的疑问:在SQL Server 2012中使用Top,sql,sql-server,Sql,Sql Server,我有一个表联系人,父表到表活动。我想为每个联系人选择最新的活动,但要获得多行 这是我的疑问: select top 30 * from Contacts o, Activity d where o.ID = d.contact and d.ID > 401061 and Last_Action is null order by d.activity_date desc 我想我需要上衣?但不确定如何在这里实施。
select top 30
*
from
Contacts o, Activity d
where
o.ID = d.contact
and d.ID > 401061
and Last_Action is null
order by
d.activity_date desc
我想我需要上衣?但不确定如何在这里实施。任何帮助都将不胜感激。这只是一个小小的猜测,因为我看不出您的表在列方面是什么样子的,但也许这个或类似的东西会起作用
select top 30 * from Contacts o,
(SELECT contact, max(activity_date) FROM Activity GROUP BY contact) d
where o.ID = d.contact And d.ID > 401061
and Last_Action is null order by d.activity_date desc
这里有一种使用notexists的方法,可以在大多数dbs上使用。您基本上是在每个联系人中选择每个活动,其中不存在更新的活动,因此它是最新的活动
select top 30 * from activity a
join contact c on c.id = a.contact
where not exists (
select 1 from activity b
where b.contact = a.contact
and b.activity_date > a.activity_date
) and last_action is null and a.id > 401061
order by a.activity_date desc
您可以使用row_number为每个联系人的活动编号。在外部查询中,您可以只筛选每个联系人的最新活动:
select top 30 *
from (
select row_number() over (
partition by o.ID
order by d.activity_date desc) as rn
, *
from Contacts o
join Activity d
on o.ID = d.contact
where d.ID > 401061
and Last_Action is null
) as SubQueryAlias
where rn = 1 -- Only last activity per contact
order by
activity_date desc
我想您应该使用子查询:
SELECT TOP 30 *
FROM
Contacts AS o,
( SELECT
contact,
MAX( activity_date ) AS activity_date
FROM
Activity
WHERE
contact > 401061 AND
Last_Action IS NULL
GROUP BY
contact
) AS d
WHERE
o.ID = d.contact
ORDER BY
d.activity_date
假设您希望每个联系人执行前30个操作,这正是CROSS APPLY发明的目的 类似于以下的情况-不确定性是因为我看不到您的数据示例
select
*
from
contacts
cross apply (
select top 30
*
from
activity
where
contacts.id = activity.contact
and 401061 < activity.id
) as _ca
where
last_action is null -- Perhaps you could move this into the CA - but we don't know which table it's from
order by
activity.activity_date desc;
编辑
使用cte
WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY contact ORDER BY activity_date DESC) rn
FROM Activity
WHERE d.ID > 401061 AND Last_Action IS NULL
)
SELECT TOP 30 *
FROM Contacts o
JOIN cte d ON o.Id = d.contact
WHERE d.rn = 1
ORDER BY cte.activity_date DESC
如果我想要30个联系人,每个联系人都有最新的活动呢?啊……我知道了。抱歉-我认为这是一个太简单的修复。Eep在1980年的连接语法。。。为什么不使用SQL-92的内部联接。。。开?我试着让它与OPs原始查询类似你是说你想要每个联系人的最新活动20多年前,在ANSI-92 SQL标准中,旧样式的逗号分隔表列表样式被正确的ANSI联接语法所取代,不鼓励使用它。你是说b.activity\u date>a.activity\u date而不是b.id>a.id?您需要一个ORDERBY子句,前30名才能正常工作。这将查找每个用户最近的30项活动。OP正在查找30个最近活动的用户。我想为联系人选择最新的活动。我想我这样解释是可以原谅的。编辑:好的,我现在看到了下面的更新aa并相应地添加了新建议。编辑后的版本应能正常工作。但是交叉应用将强制对contacts中的每一行执行子查询,因此我希望此处的其他查询速度更快。我倾向于使用此方法,因为我通常会查找超过1个最大值,而max当然无法处理。是的,也许在单一情况下,这是效率较低的。查询优化者在这里能不能做点聪明的事然而,我认为这取决于数据和执行环境——因为在一种情况下,您需要遍历所有编号的行,然后过滤它们;在另一种情况下,您可以按行查询,但会随行过滤。永远不知道查询优化器:但如果它会重写这一点,我会感到惊讶。交叉应用通常意味着程序员需要一个相关的子查询,这实际上并不比OP使用的where连接好多少。它对OP来说是有意义的,所以这就是我离开它的原因。快速指出标准已经发展,并且有更好的方法来实现相同的结果,对OP会更有帮助。@下划线\u定义得更好。。你是说视觉上?尽管我个人使用JOIN,但这似乎是我个人的偏好。
WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY contact ORDER BY activity_date DESC) rn
FROM Activity
WHERE d.ID > 401061 AND Last_Action IS NULL
)
SELECT TOP 30 *
FROM Contacts o
JOIN cte d ON o.Id = d.contact
WHERE d.rn = 1
ORDER BY cte.activity_date DESC