内心加入表自己

时间:2012-12-03 17:24:36

标签: sql sql-server sql-server-2008

我有一个使用两个标识列的表,我们称之为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()部分的子查询,因为它看起来很慢。

3 个答案:

答案 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
    )