2013-02-06 27 views
0

我有一个系统,允许用户将特定文件分配到过去或当前日期。限制是他们只能每个用户每天上传一个文件。当用户上传文件时,日期字段必须默认为当前日期,当该日期不可用时,它将以DESC顺序显示过去的第一个可用日期。以下是相关的字段名称。从数据库中获取下一个可用日期

file_id (INT - INDEX - AUTO INCREMENT) 
user_id (INT - may index this) 
upload_date (INT - stores date as a unix timestamp) 

唯一的解决办法,我真的发现将他们全部建成日期和环路DESC顺序阵列通过,直到我发现了一个空槽。但是,我觉得如果用户已经填满了过去的一千天,这可能会导致速度问题。我觉得我忽略了一个简单的解决方案。

请注意:出于某种原因,他们日期被存储为一个Unix时间戳,我明白的缺点,我不关心纠正在这个时候。

回答

1

为了让尚未使用最近的日期:

select user_id, max(date) - 1 
from (select ud.*, 
      (select max(date) from upload_date ud2 where ud2.user_id = ud.user_id and ud2.date < ud.date 
      ) as prevdate 
     from upload_date ud 
    ) ud 
where date(from_unixtime(ud.prevdate)) <> date(from_unixtime(ud.date)) - 1 or 
     ud.prevdate is null 
group by user_id 

该查询首先获得使用相关子查询任意一天以前日期。然后它将时间值转换为日期并选择前一日期有间隙的任何行。日期中最大的一个是你正在查找的日期。

该SQL未经测试,因此可能有语法错误。

+0

这是一个不错的方法。当用户在表中只有一行时会发生什么。他今天已经上传了一个文件,但之前没有上传过文件?此查询是否会返回昨天的日期? – spencer7593

+0

@ spencer7593。 。 。通过我的快速编辑,日期将被选中(我在'where'子句中检查了NULL)。 –

+0

谢谢!这也是一个非常快速的查询。 – Patcouch22

1

解决此问题的一种方法是使用经典的“返回缺少的行”查询。基本上,为了获得从数据库返回的“缺失”行,您需要一种方法来生成“缺少”行。

SELECT MAX(t.upload_date) 
    FROM mytable t 
WHERE t.upload_date <= NOW() 
    AND t.user = 'someuser' 

获得初始日期,我们打算从逆向操作:

要建立这样的查询,我们可以开始。

对于“每日一次”要求,您可能希望截断该upload_date到午夜,至少对于此查询。现在,我们假定SELECT列表中的表达式已被截断,以说明方法,而不会陷入处理unix时间戳的细节。

要生成日期的降序列表,从先前查询检索到的初始日期...

SELECT s.upload_date - INTERVAL n.d DAY AS available_date 
    FROM (SELECT MAX(t.upload_date) AS upload_date 
      FROM mytable t 
      WHERE t.upload_date <= NOW() 
      AND t.user = 'someuser' 
     ) s 
CROSS 
    JOIN (SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
     UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 
     UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 
     ) n 
ORDER BY n.d DESC 

有了这个结果,我们可以使用反连接模式来查找这些日期都没有已使用。这是一个LEFT JOIN和抛出一个谓词匹配的行:

SELECT s.upload_date - INTERVAL n.d DAY AS available_date 
    FROM (SELECT MAX(t.upload_date) AS upload_date 
      FROM mytable t 
      WHERE t.upload_date <= NOW() 
      AND t.user = 'someuser' 
     ) s 
CROSS 
    JOIN (SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
     UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 
     UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 
     ) n 
    LEFT 
    JOIN mytable u 
    ON u.upload_date = s.upload_date - INTERVAL n.d DAY 
    AND u.user = 'someuser' 
WHERE u.upload_date IS NULL 
ORDER BY n.d DESC 
LIMIT 1 

这只会回溯9天,让它回头多天,只是延长别名正线视图返回更多的连续整数。 (我们可以使用一些技巧来交叉连接以获取整数整数。)

剩下的就是工作的 “匹配” 的标准(这与MySQL DATE数据类型的作品):

ON u.upload_date = s.upload_date - INTERVAL n.d DAY 

弄成这个样子:

ON u.upload_date >= UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d+1 DAY) 
    AND u.upload_date < UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d DAY) 

并与整数把玩时间戳值来获取MySQL DATE ...

SELECT DATE(FROM_UNIXTIME(s.upload_date)) - INTERVAL n.d DAY AS available_date 
相关问题