【问题标题】:NHibernate "SELECT ... FROM (SELECT ..." CriteriaNHibernate "SELECT ... FROM (SELECT ..." 标准
【发布时间】:2010-09-09 12:55:40
【问题描述】:

我有一个使用 NHibernate Criteria 创建的 SQL 查询时遇到问题:

SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT ID FROM (SELECT MAX(ID) as ID, COLA FROM table WHERE COLB='something' GROUP BY COLA) subquery)
ORDER BY ID DESC

我最初有这个稍微简单的查询:

SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT MAX(ID) FROM table WHERE COLB='something' GROUP BY COLA)
ORDER BY ID DESC

但是,对于 NHibernate,如果我使用“GROUP BY”,它会自动将字段添加到 SELECT 语句中,我无法停止它(据我所知)。

基本上,我需要找到按任意列(在本例中为“COLA”)分组的最新记录。我正在选择最大 ID 以尝试获取最新记录(尽管这可能是其他内容,例如“MAX(UPDATED)”)。获得最新记录集后,我将进一步过滤它们(“WHERE COLC='something'”),并在结果中选择我需要的列。

如果有更好的方法来获得相同的结果,我会很高兴听到它。我的 SQL 技能充其量只是平庸。

在 NHibernate 中,我可以正确完成两个查询,但中间的部分 - “SELECT ID FROM”不起作用。

主要查询:

DetachedCriteria.For<table>()
    .Add<table>(x => x.COLC == "something")
    .Add(LambdaSubquery.Property<table>(x => x.ID).In(subquery));

还有子查询:

DetachedCriteria.For<table>()
    .Add<table>(x => x.COLB == "something")
    .SetProjection(Projections.ProjectionList()
        .Add(LambdaProjection.Max<table>(x => x.ID))
        .Add(LambdaProjection.GroupProperty<table>(x => x.COLA)));

子查询条件将“COLA”放在选择列表中(因为 GroupProperty),所以它本身无法使用,这就是为什么我需要弄清楚如何执行“SELECT ID FROM (SELECT ...”在条件中。组合时,它们会产生以下无效 SQL(因为子查询返回多于一列):

SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT MAX(ID), COLA FROM table WHERE COLB='something' GROUP BY COLA)
ORDER BY ID DESC

编辑:查看我想要的数据类型和结果也可能会有所帮助:

ID  COLA  COLB          COLC
1   1     someone       someother
2   1     something     someone     (Matches subquery, but not the max. ID)
3   1     something     something   (Matches subquery and main query)
4   2     someone       something
5   2     something     someother   (Only matches subquery)
6   3     someone       someother

我想要的结果是给定一组“COLA”的最大 ID,其中“COLB”与“something”匹配,所以我希望子查询返回 {3, 5}。最后,查询将只返回 ID 3 的记录(外部 WHERE 子句剔除了 5,因为 COLC 错误)。 COLB 和 COLC 中的实际数据无关紧要 - 我只是用它来进一步过滤结果。

我认为,在它的核心,我想要每组 COLA 的最新记录(最大 ID)

SELECT ID, COLA, COLB
FROM table
WHERE ID IN (SELECT MAX(ID) FROM table GROUP BY COLA)
ORDER BY ID DESC

【问题讨论】:

  • 你能展示你的 NHibernate 代码吗?你想要的查询到底是什么,第二个?您几乎可以使用 HQL 将其复制并粘贴到 NHibernate 中。
  • 我很想看到使用 LINQ 完成这项工作
  • @Rafael - 我添加了我能够在 NHibernate 中工作的内容。理想情况下,我想要第二个查询,但第一个是可以接受的并且产生相同的结果。第一个查询是一种解决方法,因为 NHibernate 总是将组属性放入 SELECT 列表中。我避免使用 HQL,因为我不喜欢使用“魔术字符串”。如果我绝对,肯定不能在标准上做到这一点,那么我想我没有太多选择。
  • 将组属性放入选择列表有什么关系?难道你不能在事后抓住你想要/需要的东西吗?
  • @Gage - 在这种情况下很重要,因为它会产生无效的 SQL。当子查询返回多个列时,您不能执行“ID IN (SELECT ...”。如果有办法指定子查询中要比较的列,那么我可以使用它。SQL 错误是: "当不使用 EXISTS 引入子查询时,选择列表中只能指定一个表达式。"

标签: sql nhibernate criteria


【解决方案1】:

因此,假设您正在寻找具有来自 COLA 的值的 Max ID 并且其中还包含 COLB 以及相应的 MAX ID 的记录,您可以使用类似这样的东西。

var test =
                ActiveRecordLinq.AsQueryable<table>().Where(
                    y =>
                    y.COLB == "Something" &&
                    y.ID == (from x in ActiveRecordLinq.AsQueryable<table>()
                                   where x.COLA == "Something"
                                   select x).Max(z => z.ID))

我使用我的一些对象和测试数据进行了尝试,它似乎有效。告诉我进展如何。

编辑

对于 COLA 的最大 ID 列表,您可以使用此查询。首先,我将向您展示我用于测试的那个,然后您的应该是什么样子。

我有一个电子邮件组对象,其中包含一个标题和一个 TXDX 对象,该对象具有我正在搜索的 ID。

var maxes = (from x in ActiveRecordLinq.AsQueryable<Email_Group>()
                     group x by x.Headline
                     into g
                     select new {COLA = g.Key, MaxID = g.Max(z => z.TXDX.TXDX_ID)});

你的:

var maxes = (from x in ActiveRecordLinq.AsQueryable<table>()
                     group x by x.COLA
                     into g
                     select new {COLA = g.Key, MaxID = g.Max(z => z.ID)});

我仍在处理整个查询。试图在一个电话中完成它。收到后我会发布,但现在是星期五,我在工作间隙这样做。

【讨论】:

  • 我的例子有一个很大的错误——“WHERE COLA='something' GROUP BY COLA”中的分组是多余的。我更新了这个例子。基本上,WHERE 应该过滤不同于分组内容的内容。
【解决方案2】:

我找到了一个替代解决方案,因为我不知道如何使用 NHibernate 中的标准 API 获得正确的结果 - 改用视图。

视图只使用我最初想要的查询(没有一些额外的过滤):

SELECT ID, COLA, COLB, COLC, ...
FROM table
WHERE ID IN
    (SELECT MAX(ID)
     FROM table
     GROUP BY COLA)

然后,在 NHibernate 中,我像普通表一样映射视图(除了我让它不可变):

<class name="View" table="View" lazy="false" mutable="false">
    <id name="ID" type="Int32">
        <generator class="assigned"/>
    </id>
    <property name="COLA" type="String" length="100">
        <column name="COLA" />
    </property>
    <property name="COLB" type="String" length="100">
        <column name="COLB" />
    </property>
    <property name="COLC" type="String" length="100">
        <column name="COLC" />
    </property>
    <!-- Other fields -->
</class>

并创建了要映射到的类:

public class View
{
    public virtual int ID { get; set; }
    public virtual string COLA { get; set; }
    public virtual string COLB { get; set; }
    public virtual string COLC { get; set; }
    // Other fields
}

最后,为视图创建了一个查询:

DetachedCriteria.For<View>()
    .Add<View>(x => x.COLB == "something")
    .Add<View>(x => x.COLC == "something")
    // Any other filtering criteria
    .AddOrder<View>(x => x.COLA, Order.Desc);

我宁愿在 NHibernate 中使用单个条件查询,但这完成了工作。

【讨论】:

    猜你喜欢
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 2014-02-14
    • 2014-12-28
    • 2012-06-27
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    相关资源
    最近更新 更多