【问题标题】:How can I update an interval of dates in the database (Hibernate HQL)如何更新数据库中的日期间隔(Hibernate HQL)
【发布时间】:2017-11-10 11:34:26
【问题描述】:

考虑,对于 id id 的某些特定数据库条目,数据库中的日期间隔,从 BEGIN_DATEEND_DATE,用 (BEGIN_DATE,END_DATE) 表示。

给定两个形成间隔的新日期(newBeginDatenewEndDate),我必须更新(BEGIN_DATEEND_DATE),以便生成的间隔包含所有 4 个日期。换句话说,我想添加两个区间(由于我正在添加它们,因此生成的区间可能保持不变或增长,但永远不会缩小)。

几个例子:

如果 (BEGIN_DATE,END_DATE) = (January 10,January 20),那么:

  • (BEGIN_DATE,END_DATE) + (Jan 15,Jan 25) = (Jan 10,Jan 25)

  • (BEGIN_DATE,END_DATE) + (Jan 05,Jan 15) = (Jan 05,Jan 20)

  • (BEGIN_DATE,END_DATE) + (Jan 05,Jan 25) = (Jan 05,Jan 25)

  • (BEGIN_DATE,END_DATE) + (Jan 15,Jan 15) = (Jan 10,Jan 20)

  • (BEGIN_DATE,END_DATE) + (Jan 10,Jan 13) = (Jan 10,Jan 20)

以下两个查询共同实现了这一目标。第一个更新BEGIN_DATE,第二个更新END_DATE

session.createQuery(
   "update APPOINTMENTS " +
     "set BEGIN_DATE = :newBeginDate " +
     "where " +
     "(BEGIN_DATE is null or BEGIN_DATE > :newBeginDate) " +
     "and ID = :id ")
           .setParameter("newBeginDate", newBeginDate)
           .setParameter("id", id)
           .executeUpdate();

session.createQuery(
   "update APPOINTMENTS " +
     "set END_DATE = :newEndDate " +
     "where " +
     "(END_DATE is null or END_DATE < :newEndDate) " +
     "and ID = :id ")
        .setParameter("newEndDate", newEndDate)
        .setParameter("id", id)
        .executeUpdate();

我的问题是: 如何在单个查询中完成?

【问题讨论】:

  • 您使用的是哪个 DBMS?后格雷斯?甲骨文? DB2?火鸟?
  • @a_horse_with_no_name MySQL 和 SqlServer,但这太基本了,我想没关系。
  • 你为什么要使用两个语句呢?您可以在单个 UPDATE 中完成它您的“增长,而不是收缩”到底是什么意思?请edit您的问题并添加一些示例数据和基于该数据的预期输出。 Formatted textno screen shots。不要在 cmets 中发布代码或附加信息
  • @a_horse_with_no_name 我不知道如何在一次更新中做到这一点,这正是我的问题。
  • 完成,马先生。

标签: mysql sql sql-server hibernate hql


【解决方案1】:

当涉及到更复杂的编程结构时,SQL 是有限的,所以由于您使用 Hibernate,我只需读取约会实体实例并更新其字段。这将需要两个查询,一个用于读取,一个用于更新,但它仍然只是一个更新语句,并且是最易读的解决方案。

如果您仍然只需要一个更新语句而不需要其他任何内容,则可以使用 case 将您的两个语句合并为一个:

update APPOINTMENTS 
set BEGIN_DATE = case when (BEGIN_DATE is null or BEGIN_DATE > :newBeginDate) then :newBeginDate else BEGIN_DATE end,
    END_DATE = case when (END_DATE is null or END_DATE < :newEndDate) then :newEndDate else END_DATE end
where (BEGIN_DATE is null or BEGIN_DATE > :newBeginDate or END_DATE is null or END_DATE < :newEndDate)
    and ID = :id

【讨论】:

    【解决方案2】:

    使用LEAST()GREATEST() 函数。对于 NULL,请使用 COALESCE()

    update APPOINTMENTS
    set BEGIN_DATE = coalesce(least(BEGIN_DATE, :newBeginDate), :newBeginDate),
        END_DATE   = coalesce(greatest(END_DATE, :newEndDate), :newEndDate)
    where ID = :id
    

    我认为 LEAST 和 GREATEST 不需要解释。如果旧日期为 NULL,COALESCE 将选择新日期。因此,WHERE 子句中不需要除ID = :id 之外的任何条件。

    【讨论】:

    • 非常好,简洁,回答。但是,即使 BEGIN_DATE 和 END_DATE 不变,这也会更新数据库。我在使用 InnoDB 时遇到了锁定问题,并且许多并发线程同时更新 APPOINTMENTS,所以我想减少更新次数。
    猜你喜欢
    • 1970-01-01
    • 2012-02-12
    • 2023-03-04
    • 2010-11-14
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    相关资源
    最近更新 更多