SQL 用于根据到期日期有选择地删除重复记录
SQL for selectively deleting duplicate records based on expiry dates
我有一个 MariaDB table 如下:
userid
username
email
expirydate
1
jackd
jackd@example.com
2018-10-09
2
jillf
jillf@example.com
2022-12-19
3
aaron
aaron@someone.com
2022-09-29
4
aaron1
aaron@someone.com
2021-12-19
5
jackd2
jackd@example.com
2017-11-03
6
jackd3
jackd@example.com
2019-10-09
7
simd
simd@somewhere.com
2023-03-13
8
simdb
simd@somewhere.com
2024-10-09
它允许用户使用他们的用户名登录,这是唯一的。这
其他列不是唯一的。具体来说,一个用户可以有多个
使用不同用户名的帐户,但每个帐户都可以拥有
相同的电子邮件地址。大多数用户只有一个用户名。
我们正在转向基于电子邮件而非用户名的登录系统
这意味着电子邮件现在需要是唯一的,我们需要清理
table 因为我们有重复的电子邮件。将用户与电子邮件关联
意味着用户可以有一些未过期的帐户,一些
已过期以及这两个属性的任意组合。为了
例如,电子邮件为 jackd@example.com 的用户有三个帐户,其中
都过期了,而 aaron@someone.com 有一个过期的帐户和
一个活跃账户。 simd@somewhere.com 有两个帐户都是
积极的。过期和有效的其他组合也是可能的。
我想做以下事情:
- 保留所有到期日期都在未来的重复电子邮件行(例如,保留 simd@somewhere.com 的两行)。
- 如果电子邮件与过期行和活动行混合关联,则仅删除已过期的行(例如,保留第一行
并删除 arron@someone.com).
的第二行
- 如果电子邮件与所有过期的行相关联,保留最新的(基于过期日期)行并删除其余行(例如,保留
最后一行并删除 jackd@example.com).
的前两行
- 只应定位重复的电子邮件行。
结尾 table 看起来像这样:
userid
username
email
expirydate
2
jillf
jillf@example.com
2022-12-19
3
aaron
aaron@someone.com
2022-09-29
6
jackd3
jackd@example.com
2019-10-09
7
simd
simd@somewhere.com
2023-03-13
8
simdb
simd@somewhere.com
2024-10-09
我已经尝试了所有我能想到的方法,但我总是失败。
任何帮助将不胜感激。非常感谢!
您可以通过使用 CTE 确定每个用户的到期日期顺序并确定该用户是否有任何未到期的帐户来获得您想要的结果(利用 MIN
逻辑值相当于 AND
)。然后你 select 来自该 CTE 的行,其中帐户尚未过期,或者 - 如果电子邮件只有过期帐户 - 该帐户具有最新的到期日期:
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid, username, email, expirydate
FROM rns
WHERE expirydate >= CURDATE()
OR allexpired AND rn = 1
ORDER BY userid
输出(对于您的样本数据):
userid username email expirydate
2 jillf jillf@example.com 2022-12-19
3 aaron aaron@someone.com 2022-09-29
6 jackd3 jackd@example.com 2019-10-09
7 simd simd@somewhere.com 2023-03-13
8 simdb simd@somewhere.com 2024-10-09
要从 table 中删除不需要的记录,您可以使用 DELETE
和 CTE,只要您是 运行 MariaDB 10.4 或更高版本(有一个错误这会阻止它在 MariaDB 10.3 及更早版本中工作。
DELETE users FROM users
JOIN (
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid
FROM rns
WHERE expirydate < CURDATE() AND (NOT allexpired OR rn > 1)
) del
WHERE users.userid = del.userid
对于 MariaDB 10.3 及更早版本,最简单的解决方法是创建一个包含所需行的新 table,删除旧的 table,然后将新的 table 重命名为旧的.这将是 CREATE TABLE
命令:
CREATE TABLE users2 (
`userid` INTEGER,
`username` VARCHAR(6),
`email` VARCHAR(18),
`expirydate` DATE
) AS
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid, username, email, expirydate
FROM rns
WHERE expirydate >= CURDATE()
OR allexpired AND rn = 1
ORDER BY userid
我有一个 MariaDB table 如下:
userid | username | expirydate | |
---|---|---|---|
1 | jackd | jackd@example.com | 2018-10-09 |
2 | jillf | jillf@example.com | 2022-12-19 |
3 | aaron | aaron@someone.com | 2022-09-29 |
4 | aaron1 | aaron@someone.com | 2021-12-19 |
5 | jackd2 | jackd@example.com | 2017-11-03 |
6 | jackd3 | jackd@example.com | 2019-10-09 |
7 | simd | simd@somewhere.com | 2023-03-13 |
8 | simdb | simd@somewhere.com | 2024-10-09 |
它允许用户使用他们的用户名登录,这是唯一的。这 其他列不是唯一的。具体来说,一个用户可以有多个 使用不同用户名的帐户,但每个帐户都可以拥有 相同的电子邮件地址。大多数用户只有一个用户名。
我们正在转向基于电子邮件而非用户名的登录系统 这意味着电子邮件现在需要是唯一的,我们需要清理 table 因为我们有重复的电子邮件。将用户与电子邮件关联 意味着用户可以有一些未过期的帐户,一些 已过期以及这两个属性的任意组合。为了 例如,电子邮件为 jackd@example.com 的用户有三个帐户,其中 都过期了,而 aaron@someone.com 有一个过期的帐户和 一个活跃账户。 simd@somewhere.com 有两个帐户都是 积极的。过期和有效的其他组合也是可能的。
我想做以下事情:
- 保留所有到期日期都在未来的重复电子邮件行(例如,保留 simd@somewhere.com 的两行)。
- 如果电子邮件与过期行和活动行混合关联,则仅删除已过期的行(例如,保留第一行 并删除 arron@someone.com). 的第二行
- 如果电子邮件与所有过期的行相关联,保留最新的(基于过期日期)行并删除其余行(例如,保留 最后一行并删除 jackd@example.com). 的前两行
- 只应定位重复的电子邮件行。
结尾 table 看起来像这样:
userid | username | expirydate | |
---|---|---|---|
2 | jillf | jillf@example.com | 2022-12-19 |
3 | aaron | aaron@someone.com | 2022-09-29 |
6 | jackd3 | jackd@example.com | 2019-10-09 |
7 | simd | simd@somewhere.com | 2023-03-13 |
8 | simdb | simd@somewhere.com | 2024-10-09 |
我已经尝试了所有我能想到的方法,但我总是失败。 任何帮助将不胜感激。非常感谢!
您可以通过使用 CTE 确定每个用户的到期日期顺序并确定该用户是否有任何未到期的帐户来获得您想要的结果(利用 MIN
逻辑值相当于 AND
)。然后你 select 来自该 CTE 的行,其中帐户尚未过期,或者 - 如果电子邮件只有过期帐户 - 该帐户具有最新的到期日期:
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid, username, email, expirydate
FROM rns
WHERE expirydate >= CURDATE()
OR allexpired AND rn = 1
ORDER BY userid
输出(对于您的样本数据):
userid username email expirydate
2 jillf jillf@example.com 2022-12-19
3 aaron aaron@someone.com 2022-09-29
6 jackd3 jackd@example.com 2019-10-09
7 simd simd@somewhere.com 2023-03-13
8 simdb simd@somewhere.com 2024-10-09
要从 table 中删除不需要的记录,您可以使用 DELETE
和 CTE,只要您是 运行 MariaDB 10.4 或更高版本(有一个错误这会阻止它在 MariaDB 10.3 及更早版本中工作。
DELETE users FROM users
JOIN (
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid
FROM rns
WHERE expirydate < CURDATE() AND (NOT allexpired OR rn > 1)
) del
WHERE users.userid = del.userid
对于 MariaDB 10.3 及更早版本,最简单的解决方法是创建一个包含所需行的新 table,删除旧的 table,然后将新的 table 重命名为旧的.这将是 CREATE TABLE
命令:
CREATE TABLE users2 (
`userid` INTEGER,
`username` VARCHAR(6),
`email` VARCHAR(18),
`expirydate` DATE
) AS
WITH rns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY expirydate DESC) AS rn,
MIN(expirydate < CURDATE()) OVER (PARTITION BY email) AS allexpired
FROM users
)
SELECT userid, username, email, expirydate
FROM rns
WHERE expirydate >= CURDATE()
OR allexpired AND rn = 1
ORDER BY userid