我有一个表名数据,如下所示。 mn列从1到59,然后再次从1开始 所以我有一个查询,选择这样的10个间隔
SELECT * FROM data WHERE mn IN('00','10','20','30','40','50') AND dt='2019-04-20' ORDER BY ID ASC
这可以正常工作并给出所需的结果。 但是由于某些原因,有时无法获得想要的数据00、10、20、30等,因此我希望能够选择下一个或之前的那个。
让我们说10个不可用,我希望能够在其位置选择09或11,或者说20个不可用,我希望能够在其位置选择19或21。 我该怎么办?我在IN语句中尝试了OR,它返回了有趣的结果。 请任何帮助将不胜感激谢谢
id mn dt status
---|---|----------|-----------
1 |01 |2019-04-20|1
2 |02 |2019-04-20|1
3 |03 |2019-04-20|1
4 |04 |2019-04-20|1
5 |05 |2019-04-20|1
6 |06 |2019-04-20|1
7 |07 |2019-04-20|1
8 |08 |2019-04-20|1
9 |09 |2019-04-20|1
10|10 |2019-04-20|1
11|11 |2019-04-20|1
12|12 |2019-04-20|1
13|13 |2019-04-20|1
14|14 |2019-04-20|1
15|15 |2019-04-20|1
16|16 |2019-04-20|1
17|17 |2019-04-20|1
18|18 |2019-04-20|1
19|19 |2019-04-20|1
20|21 |2019-04-20|1
21|22 |2019-04-20|1
22|23 |2019-04-20|1
答案 0 :(得分:1)
这是我想可以为您提供所需结果的查询。它使用分钟值的派生表,这些值之间的差最小,且为10分钟的最接近倍数。为了区分9和11,我们添加mn % 10 / 10
,因此此查询的结果为(例如,分钟= 8、9、10、11、12):2.8、1.9、0、1.1、2.2。我们丢弃> 2的值,因为它们应该被忽略。然后,将此派生表JOIN
添加到表中以从相应的行中选择数据:
SELECT d.*
FROM data d
JOIN (SELECT IF(hr = 23 AND mn = 59, dt + INTERVAL 1 DAY, dt) AS date,
IF(mn = 59, (hr + 1) % 24, hr) AS hour,
((mn + 1) DIV 10) % 6 AS mn10,
MIN(LEAST(ABS(mn - mn DIV 10 * 10), ABS(mn - (mn + 9) DIV 10 * 10)) + (mn % 10 / 10)) AS mndiff
FROM data
GROUP BY date, hour, mn10
HAVING mndiff < 2) dd
ON dd.date = IF(d.hr = 23 AND d.mn = 59, d.dt + INTERVAL 1 DAY, d.dt)
AND dd.hour = IF(d.mn = 59, (d.hr + 1) % 24, d.hr)
AND dd.mn10 = ((d.mn + 1) DIV 10) % 6
AND dd.mndiff = LEAST(ABS(d.mn - d.mn DIV 10 * 10), ABS(d.mn - (d.mn + 9) DIV 10 * 10)) + (d.mn % 10 / 10)
输出(用于我的demo on dbfiddle)
id mn hr dt status
2 50 23 2019-04-19 1
12 1 0 2019-04-20 1
20 11 0 2019-04-20 1
27 19 0 2019-04-20 1
更新
例如,在有第9分钟和第11分钟的数据可用(但没有第10分钟)的情况下,此查询将偏爱第11分钟的值。可以通过更改来反转
+ (mn % 10 / 10)
收件人:
- (mn % 10 / 10)
和
HAVING mndiff < 2
收件人:
HAVING mndiff < 1
所以修改后的查询是:
SELECT d.*, dd.*
FROM data d
JOIN (SELECT IF(hr = 23 AND mn = 59, dt + INTERVAL 1 DAY, dt) AS date,
IF(mn = 59, (hr + 1) % 24, hr) AS hour,
((mn + 1) DIV 10) % 6 AS mn10,
MIN(LEAST(ABS(mn - mn DIV 10 * 10), ABS(mn - (mn + 9) DIV 10 * 10)) - (mn % 10 / 10)) AS mndiff
FROM data
GROUP BY date, hour, mn10
HAVING mndiff < 1) dd
ON dd.date = IF(d.hr = 23 AND d.mn = 59, d.dt + INTERVAL 1 DAY, d.dt)
AND dd.hour = IF(d.mn = 59, (d.hr + 1) % 24, d.hr)
AND dd.mn10 = ((d.mn + 1) DIV 10) % 6
AND dd.mndiff = LEAST(ABS(d.mn - d.mn DIV 10 * 10), ABS(d.mn - (d.mn + 9) DIV 10 * 10)) - (d.mn % 10 / 10)
此查询的演示输出为:
id mn hr dt status
2 50 23 2019-04-19 1
11 59 23 2019-04-19 1
20 11 0 2019-04-20 1
27 19 0 2019-04-20 1
如您所见,它更喜欢59
值而不是01
值。
仅选择出现在10分钟标记处或之前的值(例如,按优先级依次为10、9、8、7),您可以将查询简化为:
SELECT d.*
FROM data d
JOIN (SELECT IF(hr = 23 AND mn >= 57, dt + INTERVAL 1 DAY, dt) AS date,
IF(mn >= 57, (hr + 1) % 24, hr) AS hour,
((mn + 3) DIV 10) % 6 AS mn10,
MIN(ABS(mn - (mn + 9) DIV 10 * 10)) AS mndiff
FROM data
GROUP BY date, hour, mn10
HAVING mndiff <= 3) dd
ON dd.date = IF(d.hr = 23 AND d.mn >= 57, d.dt + INTERVAL 1 DAY, d.dt)
AND dd.hour = IF(d.mn >= 57, (d.hr + 1) % 24, d.hr)
AND dd.mn10 = ((d.mn + 3) DIV 10) % 6
AND dd.mndiff = ABS(mn - (mn + 9) DIV 10 * 10)
此查询的演示输出为:
id mn hr dt status
2 50 23 2019-04-19 1
11 59 23 2019-04-19 1
19 8 0 2019-04-20 1
27 19 0 2019-04-20 1
33 27 0 2019-04-20 1
更新2
根据评论中的其他反馈,时间显示为最近的10分钟标记的时间,而不是原始时间。这会导致对查询的微小更改:
SELECT dd.mn10 * 10 AS mn, dd.hour, dd.date, d.status, d.id
FROM data d
JOIN (SELECT IF(hr = 23 AND mn >= 57, dt + INTERVAL 1 DAY, dt) AS date,
IF(mn >= 57, (hr + 1) % 24, hr) AS hour,
((mn + 3) DIV 10) % 6 AS mn10,
MIN(ABS(mn - (mn + 9) DIV 10 * 10)) AS mndiff
FROM data
GROUP BY date, hour, mn10
HAVING mndiff <= 3) dd
ON dd.date = IF(d.hr = 23 AND d.mn >= 57, d.dt + INTERVAL 1 DAY, d.dt)
AND dd.hour = IF(d.mn >= 57, (d.hr + 1) % 24, d.hr)
AND dd.mn10 = ((d.mn + 3) DIV 10) % 6
AND dd.mndiff = ABS(mn - (mn + 9) DIV 10 * 10)
ORDER BY dd.date, dd.hour, mn
updated demo的输出
mn hour date status id
0 23 2019-04-19 1 12
50 23 2019-04-19 1 2
0 0 2019-04-20 1 11
10 0 2019-04-20 1 20
20 0 2019-04-20 1 28
30 0 2019-04-20 1 34