【问题标题】:SQL Server Rank() by date, Group and Join two tables including paginationSQL Server Rank() by date, Group and Join 两个表,包括分页
【发布时间】:2017-04-07 10:31:17
【问题描述】:

在 SQL Server 中有这两个表:

购物车

id    userid    prodid    qt    date
1     21        P1        1     2017-02-18
2     21        P8        1     2017-02-19
3     21        P2        1     2017-02-20
4     22        P5        1     2017-02-21
5     22        P3        1     2017-02-22
6     23        P4        1     2017-02-23

用户

id    user_name
21    John
22    James
23    Alice
24    Lily

我想要一个表,其中仅显示具有最新日期的 文章,按 user_id 分组,有 1 列 (art_c),其中包含每个用户添加到购物车的文章数(不是 Qt,即数量),并加入了 Users 表。 另外,我想为每一行结果添加分页。

我想要的结果是这样的:

id    userid    user_name    prodid   art_c   date
3     21        John         P2       3       2017-02-20
5     22        James        P3       2       2017-02-22
6     23        Alice        P4       1       2017-02-23

最好/最快的方法是什么? 我正在使用这个请求,但我不确定它是否是好/快的方法:

With tb_a as 
(
  SELECT u_id,u_name,dat,art_c,ROW_NUMBER() OVER (ORDER BY u_name) as rgw FROM
  shopcart a
  LEFT JOIN 
  (SELECT 
       a.userid as u_id,
       b.user_name as u_name,
       Format(shop_date, 'dd.MM.yyyy HH:mm') as dat,
       RANK() OVER (PARTITION BY a.userid ORDER BY shop_date DESC) as dest_rank,
       Count(a.id) OVER (PARTITION BY a.userid ORDER BY shop_date) as art_c
       FROM 
            shopcart a
       LEFT JOIN 
            Users b on a.userid=b.id
  group by 
       a.userid,b.name,shop_date,a.id) b on a.userid=b.u_id 
  where dest_rank = 1
  group by u_id,u_name,dat,art_c
)

SELECT * FROM tb_a
WHERE rgw BETWEEN 0 AND 100 order by rgw

【问题讨论】:

  • 如果担心速度,建议不要使用FORMAT()sqlperformance.com/2015/06/t-sql-queries/…
  • 一个用户有两个最新日期相同的产品怎么办?
  • @ThorstenKettner 这只是一个例子,在数据库中我有精确到毫秒的日期时间
  • @mendosi 谢谢,我不知道FORMAT()

标签: sql sql-server database tsql group-by


【解决方案1】:

我认为你只需要在ShopCart 上使用row_number()。我会在join 之前这样做:

select u.*, sc.*
from (select sc.*,
             row_number() over (partition by sc.userid order by date desc) as seqnum
      from ShopCart sc
     ) sc join
     users u
     on sc.userid = u.id
where seqnum = 1;

对于分页,您可以添加order by,然后您可以使用offsetfetch next

编辑:

您也可以使用窗口函数获取计数:

select u.*, sc.*
from (select sc.*,
             row_number() over (partition by sc.userid order by date desc) as seqnum,
             count(*) over (partition by sc.userid) as cnt
      from ShopCart sc
     ) sc join
     users u
     on sc.userid = u.id
where seqnum = 1;

【讨论】:

  • 谢谢!您认为offsetfetch next 会比使用ROW_NUMBER() 的方法更快或更慢?
  • @MaxWater 。 . .我会使用OFFSETFETCH NEXT。它们是为分页而设计的。
  • 这太神奇了!谢谢!这种分页方法也很棒。奇怪,但我不知道。编写OFFSETFETCH 比使用WITH 子句之类的要简单得多。谢谢:)
【解决方案2】:

使用 with 语句和 Row_Number 如下,PartNo 列将按 userId 和 SeqNo 列对您的数据进行分组,以获得用户明智的计数:

;WITH S AS
(
    SELECT 
        *,
        COUNT(Id) OVER (PARTITION BY UserId) AS PartNo,
        ROW_NUMBER() OVER (PARTITION BY UserId Order BY Date DESC) AS SeqNo
    FROM @ShopCart SC
)

SELECT
    S.Id,
    S.UserId,
    U.UserName  ,
    S.ProdId,
    S.PartNo AS Art_c,
    S.Date
FROM S
LEFT JOIN @User U ON S.UserId=U.Id
WHERE S.SeqNo=1

【讨论】:

  • 非常好的和干净的解决方案。 (不过,如果您觉得这更易读,可以将 ROW_NUMBER() OVER (PARTITION BY UserId Order BY Date) 替换为 COUNT(*) OVER (PARTITION BY UserId)。)
  • @ThorstenKettner 这个解决方案和你的解决方案正在发挥作用,并给出了我想要的结果,但执行计划不同。我不知道哪个更好
  • 我也不知道,但 Gordon 和 Sandip 的查询可能比我的要快。他们只读了一次表格。
【解决方案3】:
;WITH Shopcart (id,userid,prodid,qt,date)
As
(
Select 1, 21,'P1',1, '2017-02-18' Union all
Select 2, 21,'P8',1, '2017-02-19' Union all
Select 3, 21,'P2',1, '2017-02-20' Union all
Select 4, 22,'P5',1, '2017-02-21' Union all
Select 5, 22,'P3',1, '2017-02-22' Union all
Select 6, 23,'P4',1, '2017-02-23'
)
,Users(id,[user_name])
As
(
Select 21,'John'  Union all
Select 22,'James' Union all
Select 23,'Alice' Union all
Select 24,'Lily'
)

,cte_result AS (
        SELECT c.id
            ,c.userid
            ,u.[user_name]
            ,c.prodid
            ,c.[date]
            ,COUNT(qt) OVER (PARTITION BY userid,[user_name]) art_c
            ,Row_number() OVER (PARTITION BY [user_name] ORDER BY [user_name],[date] DESC   ) Seq
        FROM Shopcart c
        INNER JOIN Users u ON u.id = c.userid
        )


SELECT id
    ,userid
    ,[user_name]
    ,prodid
    ,art_c
    ,[date]
FROM cte_result
WHERE Seq = 1
ORDER BY 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 2021-11-06
    • 2020-07-21
    • 2021-02-04
    • 1970-01-01
    相关资源
    最近更新 更多