【发布时间】:2015-02-17 16:45:38
【问题描述】:
我希望有人可以帮助我理解为什么会发生以下情况。我正在使用 hibernate 和 HQL,但是在 sqlserver 或 hsqldb 中使用从 hibernate 生成的 sql 的结果是相同的 - 我的日期没有过滤我的 JOINed 表。
问题的症结在于具有多个连接的 hql 查询,其中我要根据日期过滤器过滤其中一个连接。结果错误地包含了我的日期范围之外的数据。例如,如果 startMonthAndYear 和 endMonthAndYear 分别是 01/2015 和 12/2015,我会看到超出该范围的结果(来自 saAllocationList)(例如 01/2010)。
HQL 有一个限制,我不能在 JOIN 本身中执行子查询,我被告知这是可行的。我的问题是,我写的每一种方式似乎都应该做同样的事情..但我当然不理解 b/c 他们都没有像我想要的那样过滤日期。
我最初的 HQL 尝试在 WHERE 子句中进行过滤。
SELECT sa
FROM StaffingAssignment sa
INNER JOIN sa.workGroup wg
LEFT JOIN sa.positionRole pr
INNER JOIN sa.employee em
INNER JOIN sa.sAAllocationList sal
WHERE wg.programWorkGroupID = :id
AND sa.sAAllocationPK.dateUnit BETWEEN :startMonthAndYear AND :endMonthAndYear
上面生成的sql如下:
select staffingas0_.ID as ID1_6_, (trimmed by me) from StaffingAllocation staffingas0_
inner join WorkGroup workgroup1_ on staffingas0_.WorkGroupID=workgroup1_.ID
left outer join PositionRole positionro2_ on staffingas0_.PositionRoleID=positionro2_.ID
inner join Employee employeeex3_ on staffingas0_.EmployeeID=employeeex3_.ID
inner join SAAllocation saallocati4_ on staffingas0_.ID=saallocati4_.SAID
where workgroup1_.ProgramWorkGroupID=? and (saallocati4_.DateUnit between ? and ?)
我用几种不同的方式重写了 hsql:
在 where 子句中使用子查询来尝试获取要加载的 id 列表:
SELECT sa
FROM StaffingAssignment sa
INNER JOIN sa.sAAllocationList
INNER JOIN sa.workGroup wg
LEFT JOIN sa.positionRole pr
INNER JOIN sa.employee em
WHERE wg.programWorkGroupID = :id AND sa.id IN
(SELECT saa.staffingAllocation.id
FROM SAAllocation saa
WHERE saa.sAAllocationPK.dateUnit
BETWEEN :startMonthAndYear AND :endMonthAndYear)
生成以下sql:
select staffingas0_.ID as ID1_6_, (trimmed by me) from StaffingAllocation staffingas0_
inner join SAAllocation saallocati1_ on staffingas0_.ID=saallocati1_.SAID
inner join WorkGroup workgroup2_ on staffingas0_.WorkGroupID=workgroup2_.ID
left outer join PositionRole positionro3_ on staffingas0_.PositionRoleID=positionro3_.ID
inner join Employee employeeex4_ on staffingas0_.EmployeeID=employeeex4_.ID
where workgroup2_.ProgramWorkGroupID=? and (staffingas0_.ID in (select saallocati5_.SAID from SAAllocation saallocati5_ where saallocati5_.DateUnit between ? and ?))
在 HQL 中使用 WITH 关键字尝试在 JOIN 本身中进行过滤:
SELECT sa
FROM StaffingAssignment sa
INNER JOIN sa.sAAllocationList sal WITH sal.sAAllocationPK.dateUnit BETWEEN
:startMonthAndYear AND :endMonthAndYear
INNER JOIN sa.workGroup wg
LEFT JOIN sa.positionRole pr
INNER JOIN sa.employee em
WHERE wg.programWorkGroupID = :id
生成以下sql:
select staffingas0_.ID as ID1_6_, (trimmed by me) from StaffingAllocation staffingas0_
inner join SAAllocation saallocati1_ on staffingas0_.ID=saallocati1_.SAID and (saallocati1_.DateUnit between ? and ?)
inner join WorkGroup workgroup2_ on staffingas0_.WorkGroupID=workgroup2_.ID
left outer join PositionRole positionro3_ on staffingas0_.PositionRoleID=positionro3_.ID
inner join Employee employeeex4_ on staffingas0_.EmployeeID=employeeex4_.ID
where workgroup2_.ProgramWorkGroupID=?
但一切都返回相同的结果(包括我试图过滤的范围之外的日期)。
感谢您的阅读,如果我可以提供更多信息,这将有助于让我知道这几天一直在摆弄什么都没有显示,而且我知道这是 b/c 我对 SQL 的理解不够好。谢谢!
编辑:
我添加了一个 sqlfiddle。 http://sqlfiddle.com/#!2/8348d/2 不幸的是,sqlfiddle 做了正确的事情(即过滤掉 2010 年的数据)。谁能让它做错事,然后向我解释原因?
【问题讨论】:
-
您可能想尝试将这些日期参数显式转换为查询中的日期...
-
如果您包括表定义和示例数据,这将更容易分析,也许还有一些结果。例如,我不知道您在
dateUnit中有什么值,那么我如何判断它们是否应该包含在内?据我所知,它可能是CHAR(7),其值类似于'01/2010'。 -
类定义也不错 ;-) 可以,只是为了测试从查询中删除左连接部分吗?