我有一个使用两个标识列的表,我们称之为id和userid。 ID在每条记录中都是唯一的,而userid对用户来说是唯一的,但是在许多记录中。
我需要做的是通过userid获取User的记录,然后将该记录加入到我们为用户提供的第一条记录中。查询的逻辑如下:
SELECT v1.id, MIN(v2.id) AS entryid, v1.userid
FROM views v1
INNER JOIN views v2
ON v1.userid = v2.userid
我希望我不必将表连接到处理代码的min()部分的子查询,因为它看起来很慢。
答案 0 :(得分:13)
我想(现在还不完全清楚)你想为每个用户找到最小id
的表行,每个用户一行。
在这种情况下,您使用子查询(派生表)并将其连接到表:
SELECT v.*
FROM views AS v
JOIN
( SELECT userid, MIN(id) AS entryid
FROM views
GROUP BY userid
) AS vm
ON vm.userid = v.userid
AND vm.entryid = v.id ;
如果您愿意,也可以使用 Common Table Expression (CTE) 撰写以上内容:
; WITH vm AS
( SELECT userid, MIN(id) AS entryid
FROM views
GROUP BY userid
)
SELECT v.*
FROM views AS v
JOIN vm
ON vm.userid = v.userid
AND vm.entryid = v.id ;
对于(userid, id)
上的索引,两者都会非常有效。
使用SQL-Server,您可以使用 ROW_NUMBER()
窗口函数来编写此代码:
; WITH viewsRN AS
( SELECT *
, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY id) AS rn
FROM views
)
SELECT * --- skipping the "rn" column
FROM viewsRN
WHERE rn = 1 ;
答案 1 :(得分:1)
好吧,要使用MIN
函数和非聚合列,您必须对语句进行分组。您可以使用查询...(基于其他信息进行编辑)
SELECT MIN(v2.id) AS entryid, v1.id, v1.userid
FROM views v1
INNER JOIN views v2
ON v1.userid = v2.userid
GROUP BY v1.id, v1.userid
...但是,如果这只是一个简单的示例,并且您希望使用此查询提取更多数据,则很快就会成为不可行的解决方案。
您似乎想要的是此视图中所有用户数据的列表,每行上的链接返回到同一用户存在的“第一个”记录。上面的查询将为您提供所需的信息,但有更简单的方法可以确定每个用户的第一条记录:
SELECT v1.id, v1.userid
FROM views v1
ORDER BY v1.userid, v1.id
每个唯一身份用户的第一条记录就是您的“切入点”。我想我理解你为什么要按照你指定的方式去做,我给出的第一个查询将是合理的,但你必须考虑是否不必使用order by子句来获得正确的答案是值得的
答案 2 :(得分:-2)
edit-1:正如评论中所指出的,此解决方案还使用了一个子查询。但是,它不使用聚合函数,这些函数(取决于数据库)可能会对性能产生巨大影响。
无需子查询即可实现(见下文)。
显然,views.userid
上的索引对于表现来说具有重要价值。
SELECT v1.*
FROM views v1
WHERE v1.id = (
SELECT TOP 1 v2.id
FROM views v2
WHERE v2.userid = v1.userid
ORDER BY v2.id ASC
)