Java Hibernate HQL内部联接子选择

Java Hibernate HQL内部联接子选择,java,hibernate,hql,Java,Hibernate,Hql,我得到了以下SQL,我想将其转换为有效的HQL。这样做的问题是,不允许它根据加入子查询。尽管这些都是旧文档v3.3,但在hibernate 5.3中,这一部分似乎仍然适用 SELECT f.date, f.name, SUM(f.seats) FROM Foo f INNER JOIN (SELECT fl.date, fl.start + fl.end AS code

我得到了以下SQL,我想将其转换为有效的HQL。这样做的问题是,不允许它根据加入子查询。尽管这些都是旧文档v3.3,但在hibernate 5.3中,这一部分似乎仍然适用

SELECT f.date,
    f.name,
    SUM(f.seats) 
FROM Foo f 
        INNER JOIN (SELECT fl.date,
                        fl.start + fl.end AS code 
                    FROM Foo fl 
                    WHERE fl.date >= (SELECT MAX(earliestDate) 
                                            FROM Bar) 
                        AND fl.name = :name) fl 
        ON f.start + f.end = code 
        AND f.date = fl.date 
WHERE f.date >= (   SELECT MAX(earliestDate) 
                        FROM Bar)   
GROUP BY f.date,
    f.name 
ORDER BY f.date ASC,
    SUM(f.seats) DESC
我提出了这个HQL:

SELECT NEW com.company.project.model.FooRepresentation( f.fooId.date,
    f.fooId.name,
    SUM(f.seats)) 
FROM Foo f 
        INNER JOIN (SELECT fl.fooId.date,
                        fl.fooId.start + fl.fooId.end AS code 
                    FROM Foo fl 
                    WHERE fl.fooId.date >= (SELECT MAX(earliestDate) 
                                            FROM FooConfig) 
                        AND fl.fooId.name = :name) fl 
        ON f.fooId.start + f.fooId.end = code 
        AND f.fooId.date = fl.fooId.date 
WHERE f.fooId.date >= ( SELECT MAX(earliestDate) 
                        FROM FooConfig) 
GROUP BY f.fooId.date,
    f.fooId.name 
ORDER BY f.fooId.date ASC,
    SUM(f.seats) DESC
SELECT NEW com.company.project.model.FooRepresentation( f.fooId.date,
    f.fooId.name,
    SUM(f.seats) ) 
FROM Foo f 
WHERE EXISTS (  SELECT 1 
                FROM Foo f1 
                WHERE f.fooId.start + f.fooId.end = f1.fooId.start + f1.fooId.end 
                    AND f.fooId.date = f1.fooId.date 
                    AND f1.fooId.date >= (  SELECT MAX(earliestDate) 
                                            FROM FooConfig) 
                    AND f1.fooId.name = :name ) 
    AND f.fooId.date >= (   SELECT MAX(earliestDate) 
                            FROM FooConfig) 
GROUP BY f.fooId.date,
    f.fooId.name 
ORDER BY f.fooId.date ASC,
    SUM(f.seats) DESC
尝试执行此HQL查询会导致此异常

org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 169
这将提示at内部联接选择

在HQL中有没有连接子查询的方法?如果不是,那么实现与使用HQL的SQL相同结果的最佳方法是什么


我不太擅长将内部连接转换为允许子查询的实际where子句

我认为您的SQL查询可以重写为:

选择f.date、f.name、SUMf.seats 来自富福 哪里有 选择1 来自Foo f1 其中f.start+f.end=f1.start+f1.end f.date=f1.date 和f1.date>=从工具栏中选择MAXearliestDate 和f1.name=:name 和f.date>=从条形图中选择MAXearliestDate 按f.日期、f.名称分组 按f.date ASC、SUMf.DESC订购 这应该更容易转换为HQL,甚至可能更正确,因为原始查询似乎在自连接行之间创建了不需要的笛卡尔积


在SQL中,可能还有更好的查询方法,不必通过一次表传递来自连接Foo表。但我需要更多地了解您的实际用例,以及您正在使用的RDBMS。

在@LukasEder的回答的帮助下,我创建了以下HQL:

SELECT NEW com.company.project.model.FooRepresentation( f.fooId.date,
    f.fooId.name,
    SUM(f.seats)) 
FROM Foo f 
        INNER JOIN (SELECT fl.fooId.date,
                        fl.fooId.start + fl.fooId.end AS code 
                    FROM Foo fl 
                    WHERE fl.fooId.date >= (SELECT MAX(earliestDate) 
                                            FROM FooConfig) 
                        AND fl.fooId.name = :name) fl 
        ON f.fooId.start + f.fooId.end = code 
        AND f.fooId.date = fl.fooId.date 
WHERE f.fooId.date >= ( SELECT MAX(earliestDate) 
                        FROM FooConfig) 
GROUP BY f.fooId.date,
    f.fooId.name 
ORDER BY f.fooId.date ASC,
    SUM(f.seats) DESC
SELECT NEW com.company.project.model.FooRepresentation( f.fooId.date,
    f.fooId.name,
    SUM(f.seats) ) 
FROM Foo f 
WHERE EXISTS (  SELECT 1 
                FROM Foo f1 
                WHERE f.fooId.start + f.fooId.end = f1.fooId.start + f1.fooId.end 
                    AND f.fooId.date = f1.fooId.date 
                    AND f1.fooId.date >= (  SELECT MAX(earliestDate) 
                                            FROM FooConfig) 
                    AND f1.fooId.name = :name ) 
    AND f.fooId.date >= (   SELECT MAX(earliestDate) 
                            FROM FooConfig) 
GROUP BY f.fooId.date,
    f.fooId.name 
ORDER BY f.fooId.date ASC,
    SUM(f.seats) DESC
以前我使用ResultTransformer运行本机SQL查询:


这两个查询的结果实际上略有不同,但并不一致。在这种情况下,我的意思是,不是每一个可能的日期的结果都不同,只是有些不同。同样对于提供的参数:name,结果是一致的。我将进一步评估哪些结果更合适,但如果新结果是正确的,我不会感到惊讶。

您为什么要这样做而不是坚持使用SQL?主要是为了方便将结果转换为非@Entity类new com.company.project.model.FooRepresentationOh,新的com.company.project.model.FooRepresentation语法?但我的意思是,与重写所有代码相比,这是从Object[]映射到构造函数调用的一行代码:无论如何,我不确定这将是一个容易的重写…如果不允许子查询上的连接带来不便,那么转换起来其实并不难。它基本上只是替换列名。所以你会建议我使用本机查询并自己映射它吗?这应该更容易翻译成HQL。到目前为止,结果是一样的,虽然我的基准测试技能较低,但我的查询速度似乎在5-10毫秒左右稍快一些。我正在使用MSSQL 2017。我需要获取每个日期的每个名字,其中开始+结束在开始+结束为一个特定的名称。sumf.seats仅用于订购,我希望这是可以理解的。现在我使用了一个ResultTransformer,但可能会切换回去并使用您的查询您描述这个的方式您的查询肯定是错误的,但您可能没有注意到,因为错误可能只表现在边缘情况下的细微错误顺序中。为了加快速度,您可以在开始+结束时创建一个索引,并在日期、名称、开始时间和结束时间上添加索引。您可以使用内部连接而不是半连接…:内部联接创建笛卡尔积,这就是它们的设计目的。但你不想要笛卡尔积。我已经写过几次关于这些事情的博客,例如。简言之,在进行内部联接时,要将f表中的行重复几次,以匹配f1表中的行。这是缓慢的,并产生错误的结果。。。。在特定情况下,它可能会更快,但在其他许多情况下,它肯定是缓慢的。您的解决方案可能更快的原因是我省略了不必要的f.date>=SELECT。。。对外部查询进行筛选。SQL Server似乎无法自行推断这一点。我将编辑我的答案并重新添加过滤器。感谢所有来源。我将查询转换为HQL,目前正在对其进行测试,以检查结果是否匹配。