Skip to content

Commit d5efa45

Browse files
committed
- 补充 SqlExt.DateDiff 对其他数据库的支持;
1 parent 9487799 commit d5efa45

1 file changed

Lines changed: 101 additions & 44 deletions

File tree

FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -361,35 +361,106 @@ public static bool EqualIsNull<TValue>(TValue value1)
361361
expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} IS NULL";
362362
return false;
363363
}
364-
#endregion
364+
#endregion
365365

366-
#region 时间比较
367-
/// <summary>
368-
/// 计算两个日期之间的差异
369-
/// 时间2 - 时间1
370-
/// </summary>
371-
/// <param name="datePart"></param>
372-
/// <param name="dateTimeOffset1"></param>
373-
/// <param name="dateTimeOffset2"></param>
374-
public static long DateDiff(string datePart, DateTimeOffset dateTimeOffset1, DateTimeOffset dateTimeOffset2)
375-
{
376-
var up = expContext.Value;
366+
#region 时间比较
367+
private static void InternalDateDiff(string datePart, string arg1Name, string arg2Name)
368+
{
369+
var up = expContext.Value;
370+
var dt1 = up.ParsedContent[arg1Name];
371+
var dt2 = up.ParsedContent[arg2Name];
377372

378-
// 根据不同数据库类型定义不同的 SQL 语句
379-
if (up.DataType == DataType.SqlServer)
380-
{
381-
up.Result = $"DATEDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})";
382-
}
383-
else if (up.DataType == DataType.MySql)
384-
{
385-
up.Result = $"TIMESTAMPDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})";
386-
}
387-
else
388-
{
389-
throw new NotImplementedException("不支持的数据库类型");
390-
}
391-
return 0;
392-
}
373+
// 统一处理 datePart:部分数据库需要带单引号,部分不需要
374+
// 这里假设传入的 datePart 已经是符合 SQL Server 风格的关键字(如 year, month, day, hour 等)
375+
string part = datePart.Trim('\'', '"');
376+
377+
switch (up.DataType)
378+
{
379+
case DataType.SqlServer:
380+
case DataType.Dameng:
381+
case DataType.Xugu:
382+
up.Result = $"DATEDIFF({part}, {dt1}, {dt2})";
383+
break;
384+
385+
case DataType.MySql:
386+
case DataType.OdbcMySql:
387+
case DataType.CustomMySql:
388+
case DataType.GBase:
389+
up.Result = $"TIMESTAMPDIFF({part.ToUpper()}, {dt1}, {dt2})";
390+
break;
391+
392+
case DataType.PostgreSQL:
393+
case DataType.OdbcPostgreSQL:
394+
case DataType.CustomPostgreSQL:
395+
case DataType.KingbaseES:
396+
case DataType.ShenTong:
397+
if (part.ToLower() == "day" || part.ToLower() == "d")
398+
up.Result = $"(DATE_PART('day', {dt2} - {dt1}))";
399+
else if (part.ToLower() == "second" || part.ToLower() == "s")
400+
up.Result = $"(EXTRACT(EPOCH FROM ({dt2} - {dt1})))";
401+
else if (part.ToLower() == "minute")
402+
up.Result = $"(EXTRACT(EPOCH FROM ({dt2} - {dt1})) / 60)";
403+
else if (part.ToLower() == "hour")
404+
up.Result = $"(EXTRACT(EPOCH FROM ({dt2} - {dt1})) / 3600)";
405+
else if (part.ToLower() == "month")
406+
up.Result = $"(EXTRACT(YEAR FROM AGE({dt2}, {dt1})) * 12 + EXTRACT(MONTH FROM AGE({dt2}, {dt1})))";
407+
else if (part.ToLower() == "year")
408+
up.Result = $"(EXTRACT(YEAR FROM AGE({dt2}, {dt1})))";
409+
else
410+
throw new NotImplementedException($"PostgreSQL 不支持 datePart: {part}");
411+
break;
412+
413+
case DataType.Oracle:
414+
case DataType.OdbcOracle:
415+
case DataType.CustomOracle:
416+
if (part.ToLower() == "day" || part.ToLower() == "d")
417+
up.Result = $"TRUNC(CAST({dt2} AS DATE) - CAST({dt1} AS DATE))";
418+
else if (part.ToLower() == "month")
419+
up.Result = $"MONTHS_BETWEEN({dt2}, {dt1})";
420+
else if (part.ToLower() == "year")
421+
up.Result = $"MONTHS_BETWEEN({dt2}, {dt1}) / 12";
422+
else
423+
up.Result = $"(CAST({dt2} AS DATE) - CAST({dt1} AS DATE)) * {(part.ToLower() == "hour" ? 24 : part.ToLower() == "minute" ? 1440 : 86400)}";
424+
break;
425+
426+
case DataType.Sqlite:
427+
if (part.ToLower() == "day" || part.ToLower() == "d")
428+
up.Result = $"(julianday({dt2}) - julianday({dt1}))";
429+
else if (part.ToLower() == "second")
430+
up.Result = $"(julianday({dt2}) - julianday({dt1})) * 86400.0";
431+
else
432+
up.Result = $"CAST((strftime('%s', {dt2}) - strftime('%s', {dt1})) AS INTEGER)";
433+
break;
434+
435+
case DataType.ClickHouse:
436+
up.Result = $"dateDiff('{part.ToLower()}', {dt1}, {dt2})";
437+
break;
438+
case DataType.DuckDB:
439+
up.Result = $"date_diff('{part.ToLower()}', {dt1}, {dt2})";
440+
break;
441+
case DataType.Firebird:
442+
up.Result = $"datediff({part} from {dt1} to {dt2})";
443+
break;
444+
case DataType.TDengine:
445+
up.Result = $"timediff({dt2}, {dt1})";
446+
break;
447+
448+
default:
449+
throw new NotImplementedException($"暂不支持数据库类型: {up.DataType} 的 DateDiff 操作");
450+
}
451+
}
452+
/// <summary>
453+
/// 计算两个日期之间的差异
454+
/// 时间2 - 时间1
455+
/// </summary>
456+
/// <param name="datePart"></param>
457+
/// <param name="dateTimeOffset1"></param>
458+
/// <param name="dateTimeOffset2"></param>
459+
public static long DateDiff(string datePart, DateTimeOffset dateTimeOffset1, DateTimeOffset dateTimeOffset2)
460+
{
461+
InternalDateDiff(datePart, nameof(dateTimeOffset1), nameof(dateTimeOffset2));
462+
return 0;
463+
}
393464
/// <summary>
394465
/// 计算两个日期之间的差异
395466
/// 时间2 - 时间1
@@ -399,23 +470,9 @@ public static long DateDiff(string datePart, DateTimeOffset dateTimeOffset1, Dat
399470
/// <param name="dateTime2">时间2</param>
400471
public static long DateDiff(string datePart, DateTime dateTime1, DateTime dateTime2)
401472
{
402-
var up = expContext.Value;
403-
404-
// 根据不同数据库类型定义不同的 SQL 语句
405-
if (up.DataType == DataType.SqlServer)
406-
{
407-
up.Result = $"DATEDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})";
408-
}
409-
else if (up.DataType == DataType.MySql)
410-
{
411-
up.Result = $"TIMESTAMPDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})";
412-
}
413-
else
414-
{
415-
throw new NotImplementedException("不支持的数据库类型");
416-
}
417-
return 0;
418-
}
473+
InternalDateDiff(datePart, nameof(dateTime1), nameof(dateTime2));
474+
return 0;
475+
}
419476
#endregion
420477

421478
/// <summary>

0 commit comments

Comments
 (0)