【问题标题】:Rewrite MS SQL query for MySQL为 MySQL 重写 MS SQL 查询
【发布时间】:2018-01-31 19:25:55
【问题描述】:

不久前,一位用户发布了一个有趣的查询,该查询是为 MS SQL 编写的,它依赖于公用表表达式 (CTE)。任何人都可以就这个查询对于 MySQL 的样子提供任何指导吗?

我包含了整个示例,它还创建了一个包含一些示例数据的临时表。我只是对 MySQL 的约会查询感兴趣。在查询下方,我发布了预期的输出。

这里是原始帖子的链接: HALF-an-hour and One-hour time slot booking based on selection- c# and sql

-- Sample data from the question.
declare @Appointment table
(
    [ID] bigint not null identity(1, 1), -- Primary key.
    [BookedDate] date not null,          -- The date of the appointment.
    [Time] time(0) not null,             -- The start time of the appointment.
    [Duration] int not null              -- The length of the appointment in minutes.
);
insert @Appointment
    ([BookedDate], [Time], [Duration])
values
    ('2014-04-15', '09:00', 60),
    ('2014-04-15', '10:00', 30),
    ('2014-04-15', '17:00', 60),
    ('2014-04-15', '18:30', 30);

-- @StartTime is the time the office opens on the desired date.
-- @EndTime is the time the office closes on the desired date.
-- @Interval is the number of minutes that separate potential appointment times.
-- @DesiredDate is the date on which an appointment is requested.
-- @DesiredLength is the length of the requested appointment in minutes.
declare @StartTime time(0) = '09:00';
declare @EndTime time(0) = '21:00';
declare @Interval int = 30;
declare @DesiredDate date = '2014-04-15';
declare @DesiredLength int = 30;

-- This CTE enumerates all potential timeslots on the @DesiredDate given the above data.
with [TimeSlotCTE] as
(
    -- Base case: the first appointment slot of the day.
    select 
        [From] = @StartTime, 
        [To] = dateadd(minute, @DesiredLength, @StartTime)

    union all

    -- Recursive case: create a subsequent appointment slot as long as doing so won't
    -- take us past the office's closing time.
    select
        dateadd(minute, @Interval, [From]),
        dateadd(minute, @Interval, [To])
    from
        [TimeSlotCTE]
    where
        dateadd(minute, @Interval, [To]) <= @EndTime
)

-- Finally, we simply select every time slot defined above for which there does not
-- yet exist an overlapping appointment on the requested date.
select
    [T].[From],
    [T].[To],
    [Available] = 
        case when exists 
        (
            select 1 from @Appointment [A]
            where
                -- Forgot this line the first time around!
                [A].[BookedDate] = @DesiredDate and
                [A].[Time] < [T].[To] and
                dateadd(minute, [A].[Duration], [A].[Time]) > [T].[From]
        )
        then 'No' else 'Yes' end
from
    [TimeSlotCTE] [T];

输出

From        To          Available
09:00:00    09:30:00    No
09:30:00    10:00:00    No
10:00:00    10:30:00    No
10:30:00    11:00:00    Yes
11:00:00    11:30:00    Yes
11:30:00    12:00:00    Yes
12:00:00    12:30:00    Yes
12:30:00    13:00:00    Yes
13:00:00    13:30:00    Yes
13:30:00    14:00:00    Yes
14:00:00    14:30:00    Yes
14:30:00    15:00:00    Yes
15:00:00    15:30:00    Yes
15:30:00    16:00:00    Yes
16:00:00    16:30:00    Yes
16:30:00    17:00:00    Yes
17:00:00    17:30:00    No
17:30:00    18:00:00    No
18:00:00    18:30:00    Yes
18:30:00    19:00:00    No
19:00:00    19:30:00    Yes
19:30:00    20:00:00    Yes
20:00:00    20:30:00    Yes
20:30:00    21:00:00    Yes

谢谢!

【问题讨论】:

    标签: mysql sql sql-server common-table-expression


    【解决方案1】:

    评论太长了。

    您可以迁移到 MySQL 8+ 进行直接转换。 MySQL 现在支持公用表表达式 (CTE) 和递归 CTE。当然,代码会根据 MySQL 约定进行更改,但总体上是相同的。

    另一种方法是在两个数据库中使用numbers 表来构建约会开始。从性能的角度来看,这可能是个好主意。

    【讨论】:

      【解决方案2】:

      我是一名 DBA MSSQL,所以我将您的问题视为挑战

      好吧,我只是将您的 CT 和变量表转换为 Temporary table 并将 dateadd() 转换为 minute()

      试试这个,如果有效,请告诉我

      -- Sample data from the question.
      
      CREATE TEMPORARY TABLE IF NOT EXISTS Appointment_TMP AS
      (
          [ID] bigint not null identity(1, 1), -- Primary key.
          [BookedDate] date not null,          -- The date of the appointment.
          [Time] time(0) not null,             -- The start time of the appointment.
          [Duration] int not null              -- The length of the appointment in minutes.
      )
      insert Appointment_TMP
          ([BookedDate], [Time], [Duration])
      values
          ('2014-04-15', '09:00', 60),
          ('2014-04-15', '10:00', 30),
          ('2014-04-15', '17:00', 60),
          ('2014-04-15', '18:30', 30);
      
      -- @StartTime is the time the office opens on the desired date.
      -- @EndTime is the time the office closes on the desired date.
      -- @Interval is the number of minutes that separate potential appointment times.
      -- @DesiredDate is the date on which an appointment is requested.
      -- @DesiredLength is the length of the requested appointment in minutes.
      declare @StartTime time(0) = '09:00';
      declare @EndTime time(0) = '21:00';
      declare @Interval int = 30;
      declare @DesiredDate date = '2014-04-15';
      declare @DesiredLength int = 30;
      
      -- This CTE enumerates all potential timeslots on the @DesiredDate given the above data.
      CREATE TEMPORARY TABLE IF NOT EXISTS TimeSlotCTE AS
      (
          -- Base case: the first appointment slot of the day.
          select 
              @StartTime as From, 
              minute(@DesiredLength-@StartTime) as To
      
          union all
      
          -- Recursive case: create a subsequent appointment slot as long as doing so won't
          -- take us past the office's closing time.
          select
              minute(@Interval-From),
              minute( @Interval-To)
          from
              [TimeSlotCTE]
          where
              minute( @Interval-[To]) <= @EndTime
      )
      
      -- Finally, we simply select every time slot defined above for which there does not
      -- yet exist an overlapping appointment on the requested date.
      select
          [T].[From],
          [T].[To],
          [Available] = 
              case when exists 
              (
                  select 1 from Appointment_TMP [A]
                  where
                      -- Forgot this line the first time around!
                      [A].[BookedDate] = @DesiredDate and
                      [A].[Time] < [T].[To] and
                      minute(minute, [A].[Duration]-[A].[Time]) > [T].[From]
              )
              then 'No' else 'Yes' end
      from
          [TimeSlotCTE] [T];
      

      【讨论】:

        猜你喜欢
        • 2014-03-09
        • 1970-01-01
        • 2012-11-15
        • 2011-12-10
        • 2016-07-19
        • 2019-12-07
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多