查询以查找时间表中缺少的周数

时间:2013-07-14 13:49:38

标签: python sqlalchemy flask gaps-and-islands

我是flask和ORM的新手,我正在为我的学习编写一个示例应用程序。

我有这个型号:

class Timesheet(Base):
    __tablename__ = 'Timesheet'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('user.id'), nullable='False')
    start_date = Column(Date, nullable=False)
    end_date = Column(Date, nullable=False)
    total_time = Column(String(), nullable=False)

每个用户都需要提交每周的时间表,如果他错过了任何时间表,我们需要报告时间表。

例如 user1 时间表就像这样

Start_date | end_date
---------------------
2013-07-01 | 2013-07-08 
2013-07-08 | 2013-07-15
2013-07-22 | 2013-07-29

我们需要报告错过的(2013-07-15 | 2013-07-22)时间表

如何查询以在sqlalchemy中获得此结果?

3 个答案:

答案 0 :(得分:3)

您所面临的问题在SQL世界中名称为 gap and islands 。你可以谷歌它(有关于这个主题的大量信息)或download SQL Server MVP Deep Dives 书中免费获得第5章,该书专门针对这个问题。从本章改编的第一个差距示例到SQLAlachemy如下:

t1 = aliased(Timesheet)
t2 = aliased(Timesheet)

subq1 = session.query(
    func.min(t2.start_date)
).filter(
    (t2.start_date > t1.end_date) &
    (t2.user_id == t1.user_id)
).correlate(t1).as_scalar()

subq2 = session.query(t2).filter(
    (t2.start_date == t1.end_date) &
    (t2.user_id == t1.user_id)
).correlate(t1)

subq3 = session.query(
    func.max(t2.start_date)
).filter(
    t2.user_id == t1.user_id
).correlate(t1)

print session.query(
    t1.user_id,
    t1.end_date.label('start_date'),
    subq1.label('end_date')
).filter(
    (~subq2.exists()) &
    (t1.end_date < subq3)
).all()

答案 1 :(得分:1)

SQL查询只能查找数据库中的数据,而不能查找丢失的数据,因此要有效地找到缺少的时间段,您需要稍微重新构建数据库。

我的建议是你用数据预填表。它或多或少会像这样工作:

  • 在开始输入结束周的时间表之前,您运行的脚本会为该周的所有用户添加一个空的时间表。该脚本将添加时间表条目,例如,将total_time字段设置为空。 (顺便说一句,我注意到这个字段是一个字符串,不应该是整数吗?)。

  • 接下来,输入您从用户收到的时间表。这基本上只是用实际值更新空total_time字段,因为脚本已经创建了所有时间表的记录。

  • 现在,您可以使用查找空total_time字段的简单查询找到缺少的时间表,并打印这些记录的开始/结束日期,如果有索引,SQL可以非常有效地执行在total_time字段。

答案 2 :(得分:1)

我还要创建一个表格:在可能的过去和未来都会记录所有周的记录。

Weeks:
    id
    start_time
    end_time

然后我应该编写一个查询,它将Timesheet与Weeks表连接,并按Timesheet过滤.start_dat为null。在这种情况下,您可能希望在开始日期和结束日期列上有索引。

BTW所有用户在同一个日历周都有相同的周开始和结束日期吗? 如果是 - 我将规范化数据库,并只添加Timesheet.week_id。