【问题标题】:Excluding date range in sql query在sql查询中排除日期范围
【发布时间】:2023-04-03 01:22:02
【问题描述】:

我有要排除的年份、月份和日期的表格,如下所示

Year | Days                 | Month | Id
-----+----------------------+-------+----
2017 | 25,26,27,28,29,30,31 | 12    | 1
2018 | 1,2,3,4              | 1     | 2

我正在尝试使用以下查询排除日期,但收到一个错误提示 varchar 到 int 转换错误

Select * 
From Sample_Table st 
Inner Join Exclude_Table et On et.id = st.id 
Where st.day Not In (et.days) 

【问题讨论】:

  • 您需要将“列表”转换为实际日期值。尝试查看string_split()datefromparts()cross apply 也很有用。
  • 您成为classic blunders 之一的受害者——其中最著名的是“永远不要卷入亚洲的陆战”——但鲜为人知的是:“永远不要把表格列中的 csv 值!”
  • 当您对它们的单独部分感兴趣时,切勿存储逗号分隔的字符串。这就是说,更换你的桌子。您只需要一个包含单个日期列的排除表(即每个排除日期一行)。有了这样一个合适的表,查询将变得非常简单。顺便说一句:您的查询,如果它的语法有效,将忽略年份和月份。这是故意的吗?如果是这样,你为什么要存储年份和月份?
  • @JoelCoehoorn - 我使用 polybase 方法获取表中的显示数据,其中 azure datawarehuse 中的表直接指向 blob 存储中的 csv 文件。数据是 csv 由 SQL 查询访问。
  • @ThorstenKettner - 感谢您的建议,要求排除每年 12 月 25 日至 12 月 31 日和 1 月 1 日至 1 月 4 日的日期。

标签: sql sql-server string datetime


【解决方案1】:

一个选项使用string_split()not exists

select * 
from sample_table st 
where not exists (
    select 1
    from exclude_table et
    cross apply string_split(et.days, ',')
    where et.id = st.id and st.date = datefromparts(et.year, et.month, value)
)

这假设 sample_table(date) 存储一个实际的 date 数据类型(或类似的)。

如果您运行的是 SQL Server string_split() 不可用,则可以使用字符串函数:

select * 
from sample_table st 
where not exists (
    select 1
    from exclude_table et
    where 
        et.id = st.id 
        and et.year = year(st.date)
        and et.month = month(st.date)
        and concat(',', et.days, ',') like concat('%,', day(st.date), ',%')
)

请注意,这两种解决方案基本上都是您损坏设计的解决方法。您应该有一个单独的表来存储每个 id 的排除日期(作为日期列表或范围)。

【讨论】:

  • 感谢您的建议和解决方法,我最好使用一个单独的表格,其中包含要排除的日期列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多