DISTINCT ON与ORDER BY结合使用会返回错误的结果

时间:2018-03-19 07:46:33

标签: python postgresql sqlalchemy flask-sqlalchemy

results = Tracking.query. \
    filter(Tracking.time >= datetime.strptime(date_1, '%d-%m-%Y'),).\
    filter(Tracking.time <= datetime.strptime(date_2, '%d-%m-%Y')).\
    order_by(Tracking.device_id, desc(func.date(Tracking.time))). \
    distinct(Tracking.device_id, func.date(Tracking.time))

我有如上所述的查询,但是在这样的早期日期中产生了唯一真实的结果

[
    {
        "device_id": 1,
        "device_serial_number": "213123",
        "id": 31419,
        "latitude": "-6.1486514",
        "longitude": "106.894557",
        "time": "Mon, 19 Mar 2018 14:35:20 GMT",
        "video_id": 1,
        "video_name": "dubstep",
        "video_path": "http://localhost:5000/public/files/DubstepBirdOriginal5SecVideo.mp4"
    },
    {
        "device_id": 1,
        "device_serial_number": "213123",
        "id": 13000,
        "latitude": "-6.1509214",
        "longitude": "106.89634459999999",
        "time": "Sat, 17 Mar 2018 00:00:05 GMT",
        "video_id": 1,
        "video_name": "dubstep",
        "video_path": "http://localhost:5000/public/files/DubstepBirdOriginal5SecVideo.mp4"
    },
    {
        "device_id": 1,
        "device_serial_number": "213123",
        "id": 12988,
        "latitude": "-6.151098",
        "longitude": "106.89603483333333",
        "time": "Fri, 16 Mar 2018 23:59:43 GMT",
        "video_id": 1,
        "video_name": "dubstep",
        "video_path": "http://localhost:5000/public/files/DubstepBirdOriginal5SecVideo.mp4"
    }
]
3月16日有正确的结果,但其他人没有,如下图所示:3月17日和19日有后来必须显示的数据。

enter image description here

如果我的查询错误,我该如何修复此查询? 我尝试使用order by和group by,结果相同。

1 个答案:

答案 0 :(得分:1)

您正在将时间戳Tracking.time截断为订购日期,因此具有相同设备ID和日期部分的行将相对于彼此以未指定的顺序。然后,DISTINCT ON将选择首先出现的行。

您必须以这种或那种方式为订购添加时间。一个快速而肮脏的解决方案是将时间戳添加为第三个排序表达式:

results = Tracking.query. \
    filter(Tracking.time >= datetime.strptime(date_1, '%d-%m-%Y')).\
    filter(Tracking.time <= datetime.strptime(date_2, '%d-%m-%Y')).\
    order_by(Tracking.device_id,
             func.date(Tracking.time).desc(),
             Tracking.time.desc()).\
    distinct(Tracking.device_id, func.date(Tracking.time))

或者,您可以将时间戳转换为时间:

from sqlalchemy import Time

results = Tracking.query. \
    ...
    order_by(Tracking.device_id,
             func.date(Tracking.time).desc(),
             Tracking.time.cast(Time).desc()).\