【问题标题】:Assign rank number to rows with possible duplicates based on date根据日期将排名编号分配给可能重复的行
【发布时间】:2018-08-01 12:17:43
【问题描述】:

我有一个存储投标的下表

╔════════════╦═══════════╦══════════════════════╗
║ lot_id     ║  user_id  ║         date         ║
╠════════════╬═══════════╬══════════════════════╣
║ 123        ║ 9001      ║ 2017-08-09 14:33:55  ║
║ 123        ║ 9005      ║ 2017-08-09 14:33:55  ║
║ 123        ║ 9001      ║ 2017-08-09 14:44:55  ║
║ 124        ║ 8012      ║ 2017-08-09 14:55:55  ║
║ 124        ║ 9001      ║ 2017-08-09 14:55:55  ║
║ 124        ║ 9076      ║ 2017-08-09 14:66:55  ║
╚════════════╩═══════════╩══════════════════════╝

这个想法不是显示 user_id(出于安全原因),而是显示用户序号(顺序?),这取决于他出价的时间。 我需要一个查询,它会根据date 返回我first biddersecond bidderN bidder

这在 PHP 中会非常低效。

附:提出问题有点困难,因此欢迎在问题标题中提出任何建议。

更新 行号将不起作用。如果同一用户多次出价,则数量应相同。例如,如果同一用户第一次出价是第十次出价,则应显示first bidder

【问题讨论】:

  • @RyanWilson,我已经更新了这个问题。我的问题不同
  • 每批是否需要重新计数?
  • @SalmanA,不需要这个,因为我只会将此查询用于特定批次(其中 lot_id=123)

标签: mysql sql date


【解决方案1】:

这是一种按(最早)时间对用户进行排名的低效、蛮力解决方案。好处是它不使用用户变量或嵌套的 ORDER BY 可能产生unexpected results:

SELECT bids.lot_id, CONCAT('Bidder ', ranks.rank, ' (', bids.user_id, ')'), bids.date
FROM bids
INNER JOIN (
    SELECT curr.user_id, COUNT(prev.user_id) + 1 AS rank
    FROM (
        SELECT user_id, MIN(DATE) AS min_date
        FROM bids
        GROUP BY user_id
    ) AS curr
    LEFT JOIN (
        SELECT user_id, MIN(DATE) AS min_date
        FROM bids
        GROUP BY user_id
    ) AS prev ON prev.min_date < curr.min_date
    GROUP BY curr.user_id
) AS ranks ON bids.user_id = ranks.user_id

SQL Fiddle

【讨论】:

    【解决方案2】:

    您可以使用子查询根据日期为每个 user_id 分配一个数字。

    然后将该子查询加入投标表并使用该投标人的编号。

    示例:

    -- Sample data
    create table bidstable (lot_id int, user_id int, `date` datetime);
    insert into bidstable (lot_id, user_id, `date`) values
    (123,9001,'2017-08-09 14:33:55'),
    (123,9005,'2017-08-09 14:33:55'),
    (123,9001,'2017-08-09 14:44:55'),
    (124,8012,'2017-08-09 14:55:55'),
    (124,9001,'2017-08-09 14:55:55'),
    (124,9076,'2017-08-09 14:56:55');
    
    SELECT lot_id, concat('bidder ', n) as bidder, `date`
    FROM bidstable AS bids
    JOIN (
      SELECT user_id, @n := @n + 1 as n
      FROM bidstable
      CROSS JOIN (SELECT @n := 0) vars
      GROUP BY user_id
      ORDER BY MIN(`date`), user_id
    ) AS bidders ON bidders.user_id = bids.user_id
    ORDER BY `date`;
    

    SQL 小提琴测试here

    【讨论】:

    • 旁注。它不会将投标人名称生成为“First Bidder”、“Second Bidder”。因为我认为将这些数字翻译成文字很麻烦。
    • 没问题,我会使用“Bidder #1”之类的内容。感谢您的宝贵时间!
    • @DanielG 事实上,这个标签确实让它看起来更好。 :) 顺便说一句,在 MySql 8.x 的解决方案中,通过使用 ROW_NUMBER 窗口函数,甚至可能不需要子查询。大概。嗯,再想一想,没关系,毕竟这样做可能更棘手。
    猜你喜欢
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 2013-10-27
    • 2012-08-29
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 2015-03-28
    相关资源
    最近更新 更多