MYSQL:在同一天内排除重复的扫描日志
我试图在一天内选择不包含重复项的行。 复制的标准是:相同的用户和相同的产品\u UPC和相同的扫描日期\u ON 因此,从下表中,如果选择了扫描ID=100,则排除扫描ID=101,因为它们属于相同的用户ID和相同的产品upc,并且具有相同的扫描日期 以下是表格结构: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
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
)