【问题标题】:Converting MSSQL to MySQL将 MSSQL 转换为 MySQL
【发布时间】:2018-08-09 18:38:30
【问题描述】:

嘿,我正在尝试将 MSSQL 查询转换为 MYSQL,这给我带来了问题。这超出了我目前的舒适区。以下是我当前的查询。

WITH n AS ( 
  SELECT n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n) /* create a numbers table with 10 rows */ 
) 
, d AS ( /* Create a table with a row for each day in the date range */ 
         /* Use cross join to increase the rows in this table and then use top() to only return the rows we need */ 
   SELECT top (datediff(day, '2017-07-04', '2018-03-02')+1) 
   SessionDate = convert(datetime,dateadd(day,row_number() over(order by (select 1))-1,'2017-07-04')) 
   FROM n AS ten 
   CROSS JOIN n AS hundred /* cross join the numbers table to create 100 rows */ 
   CROSS JOIN n AS thousand /* cross join the numbers table to create 1,000 rows */ 
   CROSS JOIN n AS tenK /* cross join the numbers table to create 10,000 rows */ 
   CROSS JOIN n AS hundredK /* cross join the numbers table to create 100,000 rows */ 
   ORDER BY SessionDate 
) 
, h as ( /* add time ranges to date table */ 
    SELECT SessionDate, StartDateTime = dateadd(hour,v.s,SessionDate), EndDateTime = dateadd(hour,v.e,SessionDate), v.point 
    FROM d 
    CROSS APPLY (values 
       (0,12,'morning') 
       ,(12,17,'afternoon') 
       ,(17,24,'evening') 
    ) 
    v (s,e,point) 
) 
SELECT *
FROM h

它使用数字表并将日期分成不同的时间范围。下面是一个结果集的例子

SessionDate             | StartDateTime           | EndDateTime             | Point
2017-07-04 00:00:00.000 | 2017-07-04 00:00:00.000 | 2017-07-04 12:00:00.000 | morning
2017-07-04 00:00:00.000 | 2017-07-04 12:00:00.000 | 2017-07-04 17:00:00.000 | afternoon
2017-07-04 00:00:00.000 | 2017-07-04 17:00:00.000 | 2017-07-05 00:00:00.000 | evening
2017-07-05 00:00:00.000 | 2017-07-05 00:00:00.000 | 2017-07-05 12:00:00.000 | morning
2017-07-05 00:00:00.000 | 2017-07-05 12:00:00.000 | 2017-07-05 17:00:00.000 | afternoon
2017-07-05 00:00:00.000 | 2017-07-05 17:00:00.000 | 2017-07-06 00:00:00.000 | evening
2017-07-06 00:00:00.000 | 2017-07-06 00:00:00.000 | 2017-07-06 12:00:00.000 | morning
2017-07-06 00:00:00.000 | 2017-07-06 12:00:00.000 | 2017-07-06 17:00:00.000 | afternoon
2017-07-06 00:00:00.000 | 2017-07-06 17:00:00.000 | 2017-07-07 00:00:00.000 | evening

【问题讨论】:

  • 你输了。 MySQL 相当……在 SQL 特性方面受到限制。它没有窗口、排名或分析功能。排名通常使用相当丑陋的黑客或未记录的功能来模拟。例如,可以通过在 select 子句中增加 ... 变量来生成行号。 ...,@rownum := @rownum + 1 AS rank
  • MySql 的当前版本不支持Windowing Functions (row_number())、CTEs 或lateral joins (APPLY),这里都用到了。如果可能的话,您必须完全重新编写此查询。 CTE 问题正在为下一个完整的 MySql 版本修复,但窗口函数和横向连接仍然存在,以及完全连接、物化视图等。IMO,MySql 并不是真正的“现代”关系数据库,并且没有已经有十多年了。如果你想免费/OSS,Postgresql 可能是一个更好的选择。
  • 祝你好运。此查询中使用的大多数功能在 MySQL 中不存在。您不妨从头开始创建查询,而不是尝试将其转换为 MySQL 查询。没有CTE,没有CROSS JOIN,没有OVER(),没有CROSS APPLY
  • "MySQL 查询。没有 CTE,没有 CROSS JOIN,没有 OVER(),没有 CROSS APPLY" MySQL 支持 CROSS JOIN @Eric
  • @user2634794 您还可以创建一个 time 表,将小时与上午、下午等相匹配。之后,您只需在日历和时间之间创建笛卡尔积您想要的日期范围的表格。这将导致更简单和更快的查询

标签: mysql sql-server database-migration


【解决方案1】:

这个查询太聪明了——它使用 CTE 来生成数字序列而不是日历表,它使用 CROSS APPLY 来生成小时数而不是使用查找表来生成小时数和名称。生成的执行计划将是糟糕的

一个非常简单的日历表和一个“会话”表将允许您创建一个更简单的 T-SQL 查询,例如:

CREATE TABLE Calendar (Date date primary key not null)
GO
--Omit code to fill the calendar
CREATE TABLE Sessions (StartTime int,EndTime int, Name nvarchar(20))
GO
insert into Sessions (StartTime,EndTime,Name)
VALUES
(0,12,'morning'),
(12,17,'afternoon'),
(17,24,'evening') 


select Date as SessionDate,
    dateadd(hour,StartTime,Date) as StartTime,
    dateadd(hour,EndTime,Date) as EndTimeTime,
    Name
from Calendar,Sessions
where Date between @startDate and @endDate

范围查询将非常快,因为Date 列已编入索引。执行计划将简单地返回所有适用的日期行并将它们与 Session 行结合起来。

这可以很容易地转换为 MySQL 的方言,例如通过使用 DATE_ADD 而不是 DATEADD

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-11
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-23
    相关资源
    最近更新 更多