应使用date()函数提取日期部分再比较,如select * from orders where date(created_at) >= '2024-01-01',避免隐式转换导致时区偏差或索引失效。

WHERE子句中用DATE()提取日期部分再比较
MySQL里DATETIME或TIMESTAMP字段存的是带时分秒的完整时间,直接用>= '2024-01-01'会隐式转换,可能因时区或索引失效导致查不到预期结果。稳妥做法是用DATE()函数剥离时间部分:
SELECT * FROM orders WHERE DATE(created_at) >= '2024-01-01' AND DATE(created_at) 但要注意:<code>DATE()</code>会让<code>created_at</code>上的索引失效,大数据量时性能明显下降。<h3>更高效:用范围比较避开函数包裹列</h3><p>把条件改写成对原始列的闭区间比较,让数据库能走索引:</p><pre class="brush:php;toolbar:false;">SELECT * FROM orders WHERE created_at >= '2024-01-01 00:00:00' AND created_at 关键点:<br>• 左闭右开(<code>)比<code>更安全,避免毫秒截断误差<br>• 不依赖函数,<code>created_at</code>有索引就能命中<br>• PostgreSQL/SQL Server也适用,只是时间字面量格式略有差异(如PostgreSQL支持<code>'2024-01-01'::date</code>)<h3>不同数据库的<code>DATE()</code>行为差异</h3> <p>不是所有数据库都支持<code>DATE()</code>函数,且语义不统一:<br>• MySQL:返回<code>DATE</code>类型,可直接和字符串比较<br>• PostgreSQL:没有<code>DATE()</code>函数,得用<code>created_at::date</code>或<code>CAST(created_at AS DATE)</code><br>• SQL Server:用<code>CAST(created_at AS DATE)</code>,<code>CONVERT(DATE, created_at)</code>也可<br>• SQLite:用<code>DATE(created_at)</code>,但只对ISO8601格式(如<code>'2024-01-01 12:34:56'</code>)可靠,自定义格式需先<code>strftime()</code></p> <h3>时区问题常被忽略</h3> <p>如果数据库服务器、应用连接、字段值本身跨不同时区,<code>DATE(created_at)</code>返回的可能是错的日期。例如UTC存储的<code>'2024-01-01 23:00:00'</code>在东八区<code>DATE()</code>出来是<code>'2024-01-02'</code>。<br>• 查前先确认<code>created_at</code>存的是本地时间还是UTC<br>• 连接层设置时区(如MySQL加<code>?serverTimezone=Asia/Shanghai</code>)<br>• 必要时用<code>CONVERT_TZ()</code>(MySQL)或<code>AT TIME ZONE</code>(PostgreSQL/SQL Server)做显式转换</p></code></code>










