【问题标题】:SQL Server: Want to use between clause with dates, but dates in string form (YYYY.MM.DD)SQL Server:想要使用带日期的 between 子句,但日期为字符串形式 (YYYY.MM.DD)
【发布时间】:2026-02-04 07:10:01
【问题描述】:

帮助!我的数据库中的一列用于日期。不幸的是,我所有的日期都是字符串形式(YYYY.MM.DD)。我有一个 MASSIVE 数据库(300+GB),所以最好避免转换。

有没有办法为 YYYY.MM.DD 和 YYYY.MM.DD 之间的日期选择行?脚本会是什么样子?

谢谢!

【问题讨论】:

  • 是 MySQL 还是 SQL-Server?
  • 如果可能,我不会那样做。可以加一列吗?只是一个计算出来的,持久化和索引的:)。这样你就可以有一个快速的查询。当然可以在运行时进行字符串-日期时间转换,但要以性能为代价。
  • 相当明显的问题:为什么要将日期存储为字符串?如果可能,请修复您的架构 - 它会在很多方面让您的生活更轻松。
  • @JonSkeet:更改 300Gb 数据库上的 db 架构很可能会破坏 db 之上的层...在我的情况下,这是由其他人创建的层
  • 对此我不确定,也许专业人士会说这是否是个好主意。为什么不制作一个查找表,其中有select distinct dates(字符串格式)来自您的表格和正确格式的日期(使用当前格式的子字符串等创建)。在此之后,只需 join 这个新表与您的表在 incorrect 日期格式上,并在 where 子句中使用正确的日期格式作为参数。你觉得@JonSkeet 怎么样?它现在会给你一个快速的解决方案,但我也建议你改变你的架构。

标签: mysql sql sql-server database sql-server-2008


【解决方案1】:

如果月份和日期以前导零存储,则 BETWEEN 运算符将按预期工作。 ORDER BY 也是如此。

create table your_table (
  date_value varchar(10) not null
);

insert into your_table values
('2013.01.01'), ('2013.01.13'), ('2013.01.30'), ('2013.01.31'), 
('2013.02.01'), ('2013.02.13'), ('2013.02.28'), ('2013.02.31'), 
('2013.03.01'), ('2013.03.15'), ('2013.03.30'), ('2013.03.31');

select date_value
from your_table
where date_value between '2013.01.01' and '2013-01-31'
order by date_value;

2013.01.01
2013.01.13
2013.01.30

您的结构的主要问题之一是您失去了类型安全性。看看这个查询。

select date_value
from your_table
where date_value between '2013.02.01' and '2013.02.31'
order by date_value;

2013.02.01
2013.02.13
2013.02.28
2013.02.31

如果您使用日期或日期时间或时间戳类型的列,则 dbms 将不允许插入值“2013.02.31”,因为这不是日期域中的值。它 varchar 域中的一个值。 (“Arrrrgh!”也是如此,除非您对该列有 CHECK 约束,严重限制了可接受的值。)

【讨论】:

  • 您好。这似乎有效。但是,以下脚本正在提取正确的行数,但出于某种原因将它们全部写为 Null:Insert Into dbo.Linked (Description, Amount, Period) Select Description, Amount, coalesce(post_date,transaction_date) FROM table WHERE Description='XXX' AND post_date between '2013.03.25' AND '2013.03.31';
  • “将它们全部写为 Null”到底是什么意思?
  • 它说它已经拉了 15 行,但是当我打开查看行时,我得到所有空白/空值。因此,它以某种方式在“2013.03.25”和“2013.03.31”之间提取了正确的行数,但没有写入正确提取的信息。有任何想法吗?谢谢。
  • a) 查看 SELECT 子句返回的行。 b) 检查目标表的触发器。 c) 如果目标表中日期列的数据类型是日期类型之一,请在 SELECT 子句中使用显式转换。 (显式转换比隐式转换更好。)
【解决方案2】:

Between 在 SQL 中包含两个边界。如果这是你想要的,你可以使用between:

where col between 'YYYY.MM.DD' and 'YYYY.MM.DD'

这两个常量是您要查找的任何值。

如果列上有索引,则between(以及>>= 等)将使用该索引。您不需要转换这些值。如果您的常量是一种或另一种形式的日期,那么您可以使用date_format() 以正确的格式创建一个字符串。例如,要获取过去一周内的日期:

where col >= date_format(adddate(now(), -7), '%Y.%m.%d')

【讨论】:

    【解决方案3】:

    不是很好的解决方案,但可以工作(花费很多性能)。

    你已经按年、月、日的顺序格式化了日期(比较字符串的好顺序,没有转换为日期时间),所以你可以试试

    SELECT * FROM Table WHERE StringDate > '2013.07.10' AND StringDate < '2013.07.14' 
    

    如果 1000 年之前的日期没有前导零 ('999.07.14'),则返回错误结果。

    但我不知道它在大型数据库上是如何工作的。

    SQL Fiddle

    【讨论】:

    • 完全不错的解决方案。如果 OP 可以在他的表中添加 n/var/char 索引(额外的空间成本,dml 语句可能需要一些额外的处理时间),这可能是一个令人满意的解决方案。 +1