mysql 根据现有行选择月份的日期

hmae6n7t  于 12个月前  发布在  Mysql
关注(0)|答案(4)|浏览(93)

我有一个带有以下模式的表:

`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`bookingDate` date NOT NULL,
 PRIMARY KEY(`id`)

我需要得到当月所有少于5个预订的日期。(表示bookingDate == date的行少于5行)
我尝试逐个迭代每个月的每一天,但出于性能原因,每月执行+/- 30次查询确实没有意义。

nbysray5

nbysray51#

为了更有效地实现这一点,您可以使用单个查询。以下是解决方案的分步分解:
生成当前月份的所有日期。将生成的日期与bookingDate上的预订表连接起来。按日期分组并计算每个日期的预订。筛选出有5个或更多预订的日期。你可以这样做:

-- Step 1: Generate all dates for the current month
WITH RECURSIVE DateSequence AS (
    SELECT DATE_FORMAT(CURDATE(), '%Y-%m-01') AS dateValue -- Start from the first day of the current month
    UNION ALL
    SELECT DATE_ADD(dateValue, INTERVAL 1 DAY)
    FROM DateSequence
    WHERE DATE_ADD(dateValue, INTERVAL 1 DAY) <= LAST_DAY(CURDATE()) -- Up to the last day of the current month
)

-- Step 2, 3, and 4
SELECT ds.dateValue
FROM DateSequence ds
LEFT JOIN YourTableName t ON ds.dateValue = t.bookingDate
GROUP BY ds.dateValue
HAVING COUNT(t.id) < 5;

将YourTableName替换为预订表的名称。此查询的结果将给予您当月少于5个预订的所有日期。
这种方法的优点是,您可以在一个查询中获得结果,从而减少多个单独查询的开销。

dnph8jn4

dnph8jn42#

有许多不同的方法来解决这个问题。

选项1(实际上不是选项)

SELECT bookingDate
FROM bookings
WHERE bookingDate BETWEEN '2023-09-01' AND '2023-09-30'
GROUP BY bookingDate
HAVING COUNT(*) < 5;

这将只返回具有1、2、3或4个预订的bookingDate,因为它不知道零预订的日期。

选项二

您可以在客户端应用程序中反转上述查询并重新设置结果,取消设置结果中存在的所有日期:

SELECT bookingDate
FROM bookings
GROUP BY bookingDate
HAVING COUNT(*) >= 5;

但是,这对我来说只是感觉“笨拙”。

备选方案3

您可以从您感兴趣的完整日期列表开始,使用MariaDB的Sequence Storage Engine生成:

/* Full list of days in September 2023 based on first
 * of month and number of days in month */
SELECT '2023-09-01' + INTERVAL (seq - 1) DAY AS dt
FROM seq_1_to_30;

/* Full list of days in current month */
SELECT CURRENT_DATE - INTERVAL (DAY(CURRENT_DATE) - 1) DAY + INTERVAL (seq - 1) DAY AS dt
FROM seq_1_to_31
WHERE seq <= DAY(LAST_DAY(CURRENT_DATE));

显然,如果您已经有一个包含所有日期的日历表,或者要处理的连续集合,则不需要此步骤。
然后将LEFT JOIN转换为bookings

SELECT s.dt, COUNT(b.id) AS num_bookings
FROM (
    SELECT '2023-09-01' + INTERVAL (seq - 1) DAY AS dt
    FROM seq_1_to_30
) s
LEFT JOIN bookings b
    ON s.dt = b.bookingDate
GROUP BY s.dt
HAVING num_bookings < 5;

这里有一个db<>fiddle玩。

**注意:**您当前的表在bookingDate上缺少索引:

ALTER TABLE bookings ADD INDEX idx_booking_date (bookingDate);
qni6mghb

qni6mghb3#

希望这段代码能帮助你:
--取消当月少于5个预订的日期

SELECT DISTINCT bookingDate
FROM bookings # your-table-name
WHERE MONTH(bookingDate) = MONTH(CURRENT_DATE()) AND YEAR(bookingDate) = YEAR(CURRENT_DATE())
GROUP BY bookingDate
HAVING COUNT(*) < 5;
krugob8w

krugob8w4#

相反,您可以找到所有 * 有 * 5个或更多预订的日期,并在客户端应用程序上实现相应的逻辑。

SELECT bookingDate
FROM bookings
GROUP BY bookingDate
HAVING COUNT(bookingDate) > 4;

相关问题