MYSQL:在同一天内排除重复的扫描日志

MYSQL:在同一天内排除重复的扫描日志,mysql,sql,datetime,greatest-n-per-group,Mysql,Sql,Datetime,Greatest N Per Group,我试图在一天内选择不包含重复项的行。 复制的标准是:相同的用户和相同的产品\u UPC和相同的扫描日期\u ON 因此,从下表中,如果选择了扫描ID=100,则排除扫描ID=101,因为它们属于相同的用户ID和相同的产品upc,并且具有相同的扫描日期 以下是表格结构: SCAN_ID USER_ID PRODUCT_UPC SCANNED_ON 100 1 0767914767 2020-08-01 03:49:1

我试图在一天内选择不包含重复项的行。 复制的标准是:相同的用户和相同的产品\u UPC和相同的扫描日期\u ON

因此,从下表中,如果选择了扫描ID=100,则排除扫描ID=101,因为它们属于相同的用户ID和相同的产品upc,并且具有相同的扫描日期

以下是表格结构:

SCAN_ID      USER_ID      PRODUCT_UPC      SCANNED_ON
100          1            0767914767       2020-08-01 03:49:11
101          1            0767914767       2020-08-01 03:58:28
102          2            0064432050       2020-08-02 04:01:31
103          3            0804169977       2020-08-10 04:08:48
104          4            0875523846       2020-08-10 05:21:32
105          4            0007850492       2020-08-12 07:10:05
到目前为止,我提出的问题是:

设置@last_user=,@last_upc=,@last_date=; 选择*, @last_user作为last_user,@last_user:=user_id作为此_user, @last_upc作为last_upc,@last_upc:=产品_upc作为此_upc, @last_date作为last_date,@last_date:=日期扫描日期作为此日期 来自scansv2 拥有此用户!=最后一个用户或此upc!=上次upc或本次upc日期!=最后日期 在MySQL 8中,您可以使用


dbfiddle

在包括MySQL 8.0之前的大多数数据库中,使用子查询进行过滤是一种受支持且高效的选项:

select s.*
from scansv2 s
where s.scanned_on = (
    select min(s1.scanned_on)
    from scansv2 s1
    where 
        s1.user_id = s.user_id 
        and s1.product_upc = s.product_upc
        and s1.scanned_on >= date(s.scanned_on)
        and s1.scanned_on <  date(s.scanned_on) + interval 1 day
)

这将为您提供每个用户id、产品upc和日期的第一行,并过滤掉其他行(如果有)。

您使用的是哪个mysql版本?@nbk我使用的是5.7,但如果需要,我愿意升级。没有必要,mysql 8具有显示的窗口函数、JSON\U表和cte等,但它仍然存在一些问题。有人说速度变慢了,但mysql 6.7也很旧,过一段时间就会被弃用,所以将来应该用mysql 8进行测试。非常感谢您的时间和努力!这完全符合预期。只是一个简单的问题:我可以添加索引来加快用户定义变量版本的速度吗?我编辑我的答案,因为必须对基础数据进行排序,maswl8会自动对产品进行生成和索引,然后进行扫描,您还应该添加where子句,这样您就不会有表中的所有行
WITH rownum  AS (SELECT `SCAN_ID`, `USER_ID`, `PRODUCT_UPC`, `SCANNED_ON`,ROW_NUMBER() OVER (
          PARTITION BY `PRODUCT_UPC` 
          ORDER BY `SCANNED_ON` DESC) row_num FROM scansv2)
SELECT `SCAN_ID`, `USER_ID`, `PRODUCT_UPC`, `SCANNED_ON` FROM rownum WHERE row_num =  1 ORDER BY `SCAN_ID` 
SCAN_ID | USER_ID | PRODUCT_UPC | SCANNED_ON ------: | ------: | ----------: | :------------------ 101 | 1 | 767914767 | 2020-08-01 03:58:28 102 | 2 | 64432050 | 2020-08-02 04:01:31 103 | 3 | 804169977 | 2020-08-10 04:08:48 104 | 4 | 875523846 | 2020-08-10 05:21:32 105 | 4 | 7850492 | 2020-08-12 07:10:05
SELECT `SCAN_ID`, `USER_ID`, `PRODUCT_UPC`, `SCANNED_ON`
FROM
 (SELECT `SCAN_ID`, `USER_ID`, `SCANNED_ON`,
          IF (@product = `PRODUCT_UPC`,@row_num := @row_num + 1,@row_num := 1) row_num 
          , @product := `PRODUCT_UPC` PRODUCT_UPC
          FROM (SELECT * FROM scansv2 ORDER BY `PRODUCT_UPC`, `SCANNED_ON`) c,(SELECT @row_num := 0,@product := 0) a ) b
WHERE row_num =  1 ORDER BY `SCAN_ID` 
SCAN_ID | USER_ID | PRODUCT_UPC | SCANNED_ON ------: | ------: | ----------: | :------------------ 100 | 1 | 767914767 | 2020-08-01 03:49:11 102 | 2 | 64432050 | 2020-08-02 04:01:31 103 | 3 | 804169977 | 2020-08-10 04:08:48 104 | 4 | 875523846 | 2020-08-10 05:21:32 105 | 4 | 7850492 | 2020-08-12 07:10:05
select s.*
from scansv2 s
where s.scanned_on = (
    select min(s1.scanned_on)
    from scansv2 s1
    where 
        s1.user_id = s.user_id 
        and s1.product_upc = s.product_upc
        and s1.scanned_on >= date(s.scanned_on)
        and s1.scanned_on <  date(s.scanned_on) + interval 1 day
)