TSQL难连接问题

TSQL难连接问题,tsql,join,Tsql,Join,我正在努力解决TSQL中的一个问题,我需要从一个可能包含10个以上结果的表中获取每个用户的前10个结果 我的自然和程序思维方法是为表T中的每个用户选择按日期排序的前10个结果 每次我试图用一种基于集合的方法在脑海中表达这个问题时,我总是会遇到foreach这个词 是否可以这样做: SELECT * FROM table AS t1 INNER JOIN ( SELECT TOP 10 * FROM table AS t2 WHERE t2.id = t1.id O

我正在努力解决TSQL中的一个问题,我需要从一个可能包含10个以上结果的表中获取每个用户的前10个结果

我的自然和程序思维方法是为表T中的每个用户选择按日期排序的前10个结果

每次我试图用一种基于集合的方法在脑海中表达这个问题时,我总是会遇到foreach这个词

是否可以这样做:

SELECT *
FROM table AS t1
INNER JOIN (
    SELECT TOP 10 *
    FROM table AS t2
    WHERE t2.id = t1.id
    ORDER BY date DESC
)
甚至

SELECT (    SELECT TOP 10 *
             FROM table AS t2
             WHERE t2.id = t1.id
             ORDER BY date    )
FROM table AS t1
或者我应该考虑使用临时表来解决这个问题吗

编辑:

为了非常清楚,我需要列出表中每个用户的前10个结果,例如10*N,其中N=用户数

编辑:

作为对RBARYYOUNG建议的回应,我有一个问题,最好用代码来说明:

CREATE TABLE #temp (id INT, date DATETIME)

INSERT INTO #temp (id, date) VALUES (1, GETDATE())
INSERT INTO #temp (id, date) VALUES (1, GETDATE())

SELECT *
FROM #temp AS t1
CROSS APPLY (
 SELECT TOP 1 *
 FROM #temp AS t2
 WHERE t2.id = t1.id
 ORDER BY t2.date DESC
) AS t2

DROP TABLE #temp
运行这个,您可以看到,这并没有将结果限制在前1。。。我做错什么了吗

编辑:

我的上一个例子似乎有点混乱。下面是一个示例,显示了我想要做的事情:

CREATE TABLE #temp (id INT, date DATETIME)
INSERT INTO #temp (id, date) VALUES (1, GETDATE())
INSERT INTO #temp (id, date) VALUES (1, GETDATE())
INSERT INTO #temp (id, date) VALUES (1, GETDATE())
INSERT INTO #temp (id, date) VALUES (2, GETDATE())

SELECT *
FROM #temp AS t1
CROSS APPLY
(
    SELECT TOP 2 *
 FROM #temp AS t2
    WHERE t2.id = t1.id
    ORDER BY t2.date DESC
) AS t2

DROP TABLE #temp
这将产生:

1 2009-08-26 09:05:56.570 1 2009-08-26 09:05:56.583
1 2009-08-26 09:05:56.570 1 2009-08-26 09:05:56.583
1 2009-08-26 09:05:56.583 1 2009-08-26 09:05:56.583
1 2009-08-26 09:05:56.583 1 2009-08-26 09:05:56.583
1 2009-08-26 09:05:56.583 1 2009-08-26 09:05:56.583
1 2009-08-26 09:05:56.583 1 2009-08-26 09:05:56.583
2 2009-08-26 09:05:56.583 2 2009-08-26 09:05:56.583
如果我使用distinct:

SELECT DISTINCT t1.id
FROM #temp AS t1
CROSS APPLY
(
    SELECT TOP 2 *
 FROM #temp AS t2
    WHERE t2.id = t1.id
    ORDER BY t2.date DESC
) AS t2
我明白了

我需要

1
1
2
有人知道这是否可能吗

编辑:

下面的代码将执行此操作

WITH RowTable AS
(
SELECT 
 id, date, ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC) AS RowNum
FROM #temp 
)
SELECT *
FROM RowTable
WHERE RowNum <= 2;

我在评论中发布了,但是没有代码格式,所以看起来不太好。

这是可能的,但是使用嵌套查询会更慢

以下内容还可以找到您要查找的结果:

SELECT TOP 10 * 
FROM table as t1
INNER JOIN table as t2 
  ON t1.id = t2.id
ORDER BY date DESC

这是可能的,但是使用嵌套查询会更慢

以下内容还可以找到您要查找的结果:

SELECT TOP 10 * 
FROM table as t1
INNER JOIN table as t2 
  ON t1.id = t2.id
ORDER BY date DESC

我相信这会回答你的问题。它没有回答完全相同的问题,但我认为解决方案也会对您有效。

我相信这会回答您的问题。它没有回答完全相同的问题,但我认为这个解决方案也会对你有用。

是的,在2005年和2008年有几种不同的好方法。最类似于您正在尝试的是交叉应用:

SELECT T2.*
FROM (
    SELECT DISTINCT ID FROM table
) AS t1
CROSS APPLY (
    SELECT TOP 10 *
    FROM table AS t2
    WHERE t2.id = t1.id
    ORDER BY date DESC
) AS t2
ORDER BY T2.id, date DESC
然后,对于每个不同的[id],返回[table]中的十个最新条目或现有条目(最多10个)。如果[id]对应于一个用户,那么这应该正是您所要求的


编辑:轻微更改,因为我没有考虑到T1和T2是相同的表,因此将有多个重复的T1.ID与多个重复的T2.ID匹配。

是的,在2005年和2008年有几种不同的好方法可以做到这一点。最类似于您正在尝试的是交叉应用:

SELECT T2.*
FROM (
    SELECT DISTINCT ID FROM table
) AS t1
CROSS APPLY (
    SELECT TOP 10 *
    FROM table AS t2
    WHERE t2.id = t1.id
    ORDER BY date DESC
) AS t2
ORDER BY T2.id, date DESC
然后,对于每个不同的[id],返回[table]中的十个最新条目或现有条目(最多10个)。如果[id]对应于一个用户,那么这应该正是您所要求的


编辑:轻微更改,因为我没有考虑到T1和T2是相同的表,因此将有多个重复的T1.ID与多个重复的T2.ID匹配。

我使用了一个技巧来执行此top-N-per-group类型的查询:

SELECT t1.id
FROM table t1 LEFT OUTER JOIN table t2 
 ON (t1.user_id = t2.user_id AND (t1.date > t2.date
     OR t1.date = t2.date AND t1.id > t2.id))
GROUP BY t1.id
HAVING COUNT(*) < 10
ORDER BY t1.user_id, COALESCE(COUNT(*), 0);

这里有一个技巧,我可以使用它来执行此top-N-per-group类型的查询:

SELECT t1.id
FROM table t1 LEFT OUTER JOIN table t2 
 ON (t1.user_id = t2.user_id AND (t1.date > t2.date
     OR t1.date = t2.date AND t1.id > t2.id))
GROUP BY t1.id
HAVING COUNT(*) < 10
ORDER BY t1.user_id, COALESCE(COUNT(*), 0);

这将只返回10个结果,我需要为每个用户选择10个。啊,好的,很抱歉!您的第一个查询将比第二个查询更快。这将只返回10个结果,我需要为每个用户选择10个。啊,好的,很抱歉!第一个查询比第二个查询工作得更快。这只返回不同的T1.id?如果需要更多列,必须将它们包含在GROUPBY子句中。或者,您可以在in谓词中将上述内容用作子查询,以便获取其余的用户数据。这只返回不同的T1.ID?如果需要更多列,则必须将它们包含在GROUP BY子句中。或者,您可以将上述内容用作in谓词中的子查询,以便获得其余的用户数据。+1真棒的建议!我以前从未见过交叉申请。但是,这并没有将结果限制为10?查看最新编辑的示例。在顶部选择*放置选择n*10如果你想看到3个用户使用select top 30,但在这种情况下,每个用户必须至少有10个结果…@然后-这不完全正确,它只会限制总结果,而在查询集中仍保留一些超过10个的结果。坎佐:如果我理解你的担忧,那么,我添加的独特子查询应该可以解决这个问题。对不起,我不能从这里测试,所以我是盲编码。+1真棒的建议!我以前从未见过交叉申请。但是,这并没有将结果限制为10?查看最新编辑的示例。在顶部选择*放置选择n*10如果你想看到3个用户使用select top 30,但在这种情况下,每个用户必须至少有10个结果…@然后-这不完全正确,它只会限制总结果,而在查询集中仍保留一些超过10个的结果。坎佐:如果我理解你的担忧,那么我添加的独特子查询应该可以解决这个问题对不起,我不能从这里进行测试,
所以我是瞎编的。不完全是——我只想选择前10名或更少的结果,这个答案似乎只有在排名低于数字时才会选择。这似乎相当类似于一个HAVING COUNT*短语?不完全一样-我只想选择前10名或更少的结果,这个答案似乎只有在排名低于数字时才选择。这似乎相当类似于一个有计数*的短语?你没有要求它限制结果而不是前1名,是吗?您要求它将结果限制为每个用户的前1名,这是不同的。但我确信我的原始答案并没有说明源表中的用户ID是重复的:现在更正。@rbaryyoung-Sorry mate。我已经添加了一个示例来确切地说明我想要什么。我有点太简单了:你没有要求它限制结果而不是前1名,是吗?您要求它将结果限制为每个用户的前1名,这是不同的。但我确信我的原始答案并没有说明源表中的用户ID是重复的:现在更正。@rbaryyoung-Sorry mate。我已经添加了一个示例来确切地说明我想要什么。这对我来说有点简单化了:由于某种原因,这与我给出的示例表不符,例如SELECT id、date、,分区上的行数按id排序按日期DESC AS RowNum FROM temp其中RowNum几个小时来我一直在尝试解决类似问题的各种方法-使用ROW_数方法只得到了一个3分钟到10秒的查询。由于某种原因,我给出的示例表不适用,例如SELECT id,date,分区上的行数按id排序按日期DESC AS RowNum FROM temp,在这里RowNum我几个小时来一直在处理一个类似的问题,尝试各种方法来解决它-使用ROW_数方法只得到一个3分钟到10秒的查询。