我在Stackoverflow上已经阅读了有关FROM_UNIXTIME使用的各种问题,但没有一个直接处理我想要做的事情。我有一个来自php的变量的时间戳(已经重新格式化 - 例如2014年3月25日)到一个函数,该函数使用数据库查询来确定数据库中是否有其他条目具有相同的日期(而不是时间)。我使用MySql运行各种方法来格式化和比较时间戳条目,最后得到以下内容但我知道它不是非常有效。有谁知道更好的方法来实现这个目标?
FROM_UNIXTIME(sd.timestart, "%e %M %Y") = ?'
我的数组中用于比较的变量是上面列出的日期格式。这实现了我想要的东西,但是,我不认为这是完成这项工作的最有效方法。任何建议和/或想法将不胜感激。
*的 修改 * 我的时间戳存储为整数,因此我尝试使用:
$thissessiondate = strtotime($date->timestart, strtotime('today'));
和
$tomorrowdate = strtotime($date->timestart, strtotime('tomorrow'));
修剪到午夜但是得到一个错误(strtotime()期望参数2很长)当我今天移动时#39;到第一个参数位置,我得到转换到晚上11点而不是0点......?我取得了一些进展,但我对PHP和MySQL的非常不完整的知识阻碍了我。
答案 0 :(得分:1)
如果可以避免,请不要在表达式中包含谓词中使用的列。
将您的谓词放在裸列上以使索引范围扫描成为可能。您希望尽可能在谓词的文字侧进行数据类型转换。
STR_TO_DATE函数最方便。
假设timestart
列是DATE,DATETIME或TIMESTAMP(它确实应该是,如果它代表一个时间点。)
WHERE sd.timestart >= STR_TO_DATE( ? , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( ? , "%e %M %Y") + INTERVAL 1 DAY
实际上,正在做的是将传入的字符串作为STR_TO_DATE函数的第一个参数传入,MySQL将根据指定为第二个参数的格式将该字符串转换为DATETIME。这有效地成为MySQL可以用来与列中存储的值进行比较的文字。
如果有适当的索引可用,MySQL会考虑索引范围扫描操作来满足该谓词。
您需要传递两次相同的值,但这并不是真正的问题。
在第二行,我们只是将一天添加到相同的值。所以MySQL看到的是:
WHERE sd.timestart >= STR_TO_DATE( '25 March 2014' , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY
在表现方面,这相当于:
WHERE sd.timestart >= '2014-03-15 00:00:00'
AND sd.timestart < '2014-03-16 00:00:00'
如果你反过来这样做,并在一个函数中包装timestart,那就需要MySQL来评估每一行上的函数(或者至少在每一行上都没有&#39; t首先被另一个谓词过滤掉。)
重要提示
请注意,MySQL会将日期时间值解释为位于MySQL连接的 timezone 中,默认为MySQL服务器的时区设置。 MySQL将在时区的当前设置中解释日期时间文字。例如,如果MySQL时区设置为+00:00,那么datetime文字将被解释为UTC。
我假设格式字符串与传入的数据匹配,我不使用%e或%m。 %Y是四位数年份。 (格式元素列表在MySQL文档中,在DATE_FORMAT
函数下。
参考:http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
如果您的timestart列是INTEGER或其他数字数据类型,表示自时代开始以来的秒数或某个其他时间单位,您可以使用相同的方法来获得性能优势。
在谓词中,引用表中的裸列,并在文字方面进行所需的任何转换。
如果你没有使用MySQL函数来转换到1970年1月1日以来的&#34;秒UTC&#34;当插入行时(这实际上是TIMESTAMP数据类型在内部执行的操作),我也不建议使用MySQL函数在查询中进行转换。
如果您正在从日期和时间转换为整数类型&#34;时间戳&#34;在PHP中,我也可以在PHP中进行逆转换,然后修剪到午夜并在PHP中添加一天。
在这种情况下,您的MySQL查询将是简单的形式:
WHERE sd.timestart >= ?
AND sd.timestart < ?
您将传递适当的整数值,以与INTEGER时间戳列进行比较。
请注意,MySQL确实提供了自1970年1月1日UTC&#34;以来转换为&#34;秒的功能,因此如果timestart是自1970年1月1日UTC以来的秒数,则此类内容有效:
WHERE sd.timestart >= UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y"))
AND sd.timestart < UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY)
再次但是...... ,请注意时区转换问题;如果MySQL数据库具有与Web服务器不同的时区设置。如果你打算存储&#34;整数&#34;,那么我不会用MySQL做的转换来解决这个问题,这可能与网络服务器的转换功能完全不同。
答案 1 :(得分:0)
如果您将日期存储为int时间戳,则可以执行此操作
round(sd.timestart/86400)=round(UNIX_TIMESTAMP(NOW())/86400)
这将使您的数据库中的所有内容从同一天开始。
例如:
SELECT id FROM uploads WHERE (approved=0 OR approved is NULL) AND round(uploads.date/86400)<=round(UNIX_TIMESTAMP(NOW())/86400) order by uploads.date DESC LIMIT 20
将显示今天和前几天的所有上传内容,而不会显示未来的上传内容。 86400是一天中的秒数。