如何解决使用 INTERVAL 查询日期范围
我们使用 clickhouse 作为我们的数据库,并且有一个列类型为 DateTime(
UTC)
的表。
我需要查询日期范围,例如这样的:
SELECT *
FROM some_table
WHERE date_time_column BETWEEN ? AND ?
我有参数 Start
和 End
,它们的类型为 time.Time
,但客户要求附加选项:
基本上,他们想提供 Start
和一个偏移量。偏移量可以是天、小时、周或月。
由于我是新员工,之前从未与 clickhouse 合作过,所以我来这里寻求帮助。
我解决问题的努力:
我调查了 clickhouse 文档并发现了 INTERVAL。
它看起来很适合我的任务,因为我有这样的想法:
SELECT *
FROM some_table
WHERE date_time_column BETWEEN ? AND ? + INTERVAL ? MONTH + INTERVAL ? WEEK + INTERVAL ? DAY + INTERVAL ? HOUR
这样我就可以对不需要的参数使用零,例如:
-
如果我们需要 3 小时,我们会在伪代码中得到类似的东西:
sqlx.db.Query(SELECT * FROM some_table WHERE date_time_column BETWEEN ? AND ? + INTERVAL ? MONTH + INTERVAL ? WEEK + INTERVAL ? DAY + INTERVAL ? HOUR,Start,3)
-
如果我们需要 3 小时 2 天,我们会在伪代码中得到类似的内容:
sqlx.db.Query(SELECT * FROM some_table WHERE date_time_column BETWEEN ? AND ? + INTERVAL ? MONTH + INTERVAL ? WEEK + INTERVAL ? DAY + INTERVAL ? HOUR,2,3)
问题:
- 我的想法是否高于可行的解决方案?
- 如果不是,你能告诉我如何实现上述要求吗?
除了 clickhouse 数据库,我们还使用 Golang 和 sqlx 库与 clickhouse 通信。
解决方法
对我来说,你的决定看起来不错。
我会通过计算 sql-script 之外的 Stop-date 来简化它:
// controller
[HttpPost]
public IActionResult Save([FromForm] CompanyViewModel company,IFormFileCollection files)
{
// TODO
return Ok();
}
// startup.cs
services.AddControllers(options => {
options.ModelBinderProviders.Insert(0,new FromFormModelBinderProvider());
});
public class FromFormModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) {
throw new ArgumentNullException(nameof(context));
}
if (!context.Metadata.ModelType.IsPrimitive &&
!context.Metadata.ModelType.Equals(typeof(string)) &&
context.Metadata.BindingSource.Id == "Form") {
return new FromFormModelBinder();
}
return null;
}
}
public class FromFormModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// Fetch the value of the argument by name and set it to the model state
string fieldName = bindingContext.FieldName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);
if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
else bindingContext.ModelState.SetModelValue(fieldName,valueProviderResult);
// Do nothing if the value is null or empty
string value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value)) return Task.CompletedTask;
try {
// Deserialize the provided value and set the binding result
var options = bindingContext.ActionContext.HttpContext.RequestServices.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value;
object result = JsonConvert.DeserializeObject(value,bindingContext.ModelType,options.SerializerSettings);
bindingContext.Result = ModelBindingResult.Success(result);
}
catch (JsonException) {
bindingContext.Result = ModelBindingResult.Failed();
}
return Task.CompletedTask;
}
}
import (
"time"
)
Start := ..
Stop := Start.AddDate(0,months,days + weeks*7).Add(time.Hour * time.Duration(hours))
这种方式看起来更易于维护(不需要 CH SQL 知识)和可测试(从单元测试的角度来看)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。