选择与标准匹配的顶级项目的方法

时间:2010-05-28 18:08:10

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

编辑:道歉,这是一个MSSQL2008问题。

我有一个SQL问题,我经常遇到反对,通常只是用嵌套查询来解决。我希望有人能提出更优雅的解决方案。

我经常需要为用户选择一个结果集,条件是它是最新的,或者是最大的或者其他什么。

例如:他们创建了完整的页面列表,但我只想要他们应用于页面的最新名称。碰巧的是,数据库包含每个页面的许多条目,并且只需要最新的条目。

我一直在使用嵌套的选择:

SELECT pg.customName, pg.id
FROM (
     select id, max(createdAt) as mostRecent
     from pages
     where userId = @UserId
     GROUP BY id
) as MostRecentPages
JOIN pages pg
ON pg.id = MostRecentPages.id
AND pg.createdAt = MostRecentPages.mostRecent

是否有更好的语法来执行此选择?

6 个答案:

答案 0 :(得分:2)

看起来像你想要的

SELECT id, customname
FROM (SELECT id, customname,
             row_number() OVER(PARTITION BY id ORDER BY createdat DESC) as pos
      FROM pages
      WHERE pages.userid = @UserId
     ) x
WHERE x.row_number = 1

(我假设您正在使用来自@UserId参数的SQL Server.row_number()将适用于SQL Server 2005,而上述内容也适用于Oracle,Postgresql 8.4 ...)

这将按用户ID选择所有页面,并计算最近使用排序的页面。另一种选择是:

SELECT id, (SELECT TOP 1 customname
            FROM pages pages_inner
            WHERE pages_inner.id = pages_outer.id
            ORDER BY pages_inner.createdat DESC) as customname
FROM (SELECT DISTINCT id FROM pages WHERE pages.userid = @UserId) pages_inner

哪种方法更好取决于每个用户ID与每个用户ID的页数相比有多少页面行数,我猜。

答案 1 :(得分:1)

我不确定更好,但你可以尝试不同的语法

SELECT pg.customName, pg.id
FROM pages pg
WHERE userId = @UserId  
AND NOT EXISTS 
        (
         SELECT * FROM pages pg2
         WHERE pg2.UserId = pg.UserId
         AND pg2.id = pg.id
         AND pg2.createdAt > pg.createdAt
         )

另一种选择是外部加入,如Bill Karwin在这里的回答How to get all the fields of a row using the SQL MAX function?

答案 2 :(得分:1)

对于什么数据库(包括版本)?您发布的内容可能是MySQL,SQL Server或Sybase ......

使用:

SELECT pg.customName, 
       pg.id
  FROM PAGES pg
  JOIN (SELECT t.userid, 
               MAX(t.createdAt) as mostRecent
          FROM PAGES t
      GROUP BY t.userid) x ON x.id = pg.id
                          AND x.mostRecent = pg.createdAt
                          AND x.userid = @UserId 

这是便携式查询的最佳方法,假设列引用正确。但是有限制数据集的替代方案 - SQL Server使用TOP,MySQL / Postgre / SQLite使用LIMIT,Oracle使用ROWNUM

什么是最好的取决于您的数据和&各个优化器如何看待它以及您的需求(可移动与否)。检查相应数据库的说明计划,以查看查询的效率。

答案 3 :(得分:0)

您使用的是Oracle吗?尝试查看使用分析函数的此查询是否适合您。 (现在不能访问db,所以无法测试自己。)

SELECT DISTINCT pg.id, 
FIRST_VALUE(pg.customName) OVER (PARTITION BY pg.id ORDER BY pg.createdAt DESC) AS customName
FROM pages pg

答案 4 :(得分:0)

假设SQL Server和您的Pages表如下:

CREATE TABLE Pages (
    Id int IDENTITY(1, 1) PRIMARY KEY
    , CustomName nvarchar(20) NOT NULL
    , CreatedAt datetime NOT NULL DEFAULT GETDATE()
    , UserId int references Users(Id)
)

我会做以下事情:

select TOP 1 p.Id as PageId
        , p.CustomName
    from Pages p
    where p.UserId = @UserId
    order by p.Created desc

甚至:

select TOP 1 p.Id as PageId
        , p.CustomName
        , MAX(p.CreatedAt) DateTimeCreated
    from Pages p
    where p.UserId = @UserId
    group by p.Id
        , p.CustomName

我希望这有帮助! (如果没有,请提供进一步的详细信息,以便我们可以更好地帮助

答案 5 :(得分:-1)

我不知道你的桌子是什么样的

Select top 1  pg.createdAt
             ,pg.customName
             ,pg.id
from          table pg
where         pg.UserId = @UserId
order by      pg.createdAt Desc

我需要在您的桌子上提供更多信息