我有一个查询,用于在特定时间点(从vehicle_sightings
表中)获取有关车辆所有者的信息。我附上了以下查询部分的片段:
SELECT
sighting_id
FROM
vehicle_sightings
INNER JOIN
vehicle_vrn ON vehicle_sightings.plate = vehicle_vrn.vrnno
INNER JOIN
vehicle_ownership ON vehicle_vrn.fk_sysno = vehicle_ownership.fk_sysno
WHERE
vehicle_sightings.seenDate >= vehicle_ownership.ownership_start_date
AND (vehicle_sightings.seenDate <= vehicle_ownership.ownership_end_date
OR vehicle_ownership.ownership_end_date IS NULL
OR vehicle_ownership.ownership_end_date = '0001-01-01 00:00:00')
这适用于车辆历史上只有一个车主的大多数情况。但是,在某些情况下ownership_end_date
字段未填写(大多数情况下 填写,因为它表示车辆已转手,并且来自该阶段转发给新主人)。在未填写(或保留默认值)的情况下,将返回该所有权历史记录的所有条目,例如以下情况:
在上面的情况下,查询返回这两个记录,因为seenDate
适合它们,因为未填写结束日期(在这种情况下具有默认值)。因此,在这些情况下,我需要修改我的查询以返回具有最高ownership_start_date
的记录。
我尝试通过在最后添加以下内容来实现此目的:
GROUP BY sighting_id HAVING seenDate >= MAX(ownership_start_date)
然而这并不起作用,因为返回了更少的记录。有没有一种干净的方法可以实现,也许没有GROUP BY?
答案 0 :(得分:3)
首先,使用默认日期是一个非常糟糕的主意。您应该已经知道了这一点,因为现在您在某些情况下会对硬编码日期进行编码。当另一个开发人员对数据库进行编码时(或者甚至是你以后的编码),他们现在必须知道并记住他们必须根据某些硬编码的日期对异常进行编码。
此外,您的ownership_end_date
应始终位于ownership_start_date
之后,此“默认”日期现在将违反。如果您不知道日期或日期尚不存在,那么它应该是NULL
- 这正是NULL
的用途 - 未知。
对于您的具体问题,您可以使用LEFT JOIN
执行此操作,以检查符合条件的其他所有者,如果存在更好的行,则排除该行。你没有提供你所有的桌子结构,而且你是否只是想在最近看到的日期之前想要最新的所有者(我做了什么)或者所有拥有这辆车的车主在看见日期之后都不清楚了,所以我不知道这是否有效,但是这样的话:
SELECT
VS.sighting_id -- ALWAYS use table aliases or prefixes for clarity
FROM
vehicle_sightings VS
INNER JOIN vehicle_vrn VRN ON VRN.vrnno = VS.plate
INNER JOIN vehicle_ownership VO ON VO.fk_sysno = VRN.fk_sysno
LEFT OUTER JOIN vehicle_ownership VO2 ON
VO2.fk_sysno = VRN.fk_sysno AND
VO2.ownership_start_date <= VS.seenDate AND
(
VO2.ownership_end_date >= VS.seenDate OR
VO2.ownership_end_date IS NULL OR
VO2.ownership_end_date = '0001-01-01 00:00:00'
) AND
VO2.ownership_start_date > VO.ownership_start_date
WHERE
VS.seenDate >= VO.ownership_start_date AND
(
VS.seenDate <= VO.ownership_end_date OR
VO.ownership_end_date IS NULL OR
VO.ownership_end_date = '0001-01-01 00:00:00'
) AND
VO2.id IS NULL -- Or some other non-nullable column
最后一点需要注意:决定命名约定并坚持下去(例如seenDate
vs ownership_end_date
)并使用有意义的名称(什么是fk_sysno
??)< / p>
答案 1 :(得分:1)
这是一个不需要子查询的解决方案。它确保不存在大于返回记录的所有权记录。
SELECT
sighting_id
FROM
vehicle_sightings
INNER JOIN
vehicle_vrn ON vehicle_sightings.plate = vehicle_vrn.vrnno
INNER JOIN
vehicle_ownership ON vehicle_vrn.fk_sysno = vehicle_ownership.fk_sysno
LEFT OUTER JOIN
vehicle_ownership vo2 ON vo2.fk_sysno = vehicle_ownership.fk_sysno
AND vo2.ownership_start_date > vehicle_ownership.ownership_start_date
WHERE
vehicle_sightings.seenDate >= vehicle_ownership.ownership_start_date
AND (vehicle_sightings.seenDate <= vehicle_ownership.ownership_end_date
OR vehicle_ownership.ownership_end_date IS NULL
OR vehicle_ownership.ownership_end_date = '0001-01-01 00:00:00')
AND vo2.fk_sysno IS NULL