【问题标题】:query to return a day's records from datetime field查询从日期时间字段返回一天的记录
【发布时间】:2014-03-05 07:04:26
【问题描述】:

在使用 hibernate 和 jpa 的 spring mvc 应用程序中,我有一个查询需要返回日期在指定日期内的所有记录。 day 最终来自yyyy-mm-dd 格式的url 参数,并存储在joda localdate 对象中。按天搜索其记录的实体将 joda DateTime 作为正在搜索的属性的类型。底层 MySQL 数据库将日期信息存储在 TimeStamp 字段中。为了从localdate 转换为datetime,我阅读了the localdate api 并尝试了day.toDateTimeAtStartOfDay(),但这会将参数范围缩小太多。我需要在一天中的 24 小时内获取所有记录,而不仅仅是一天中第一秒的记录。如何构造查询,使其返回 TimeStamp 字段中指定日期的每条记录,包括该指定日期内的所有时间?

这里是在 jpa 存储库中包含查询的方法:

@Override
public Collection<Encounter> findByDay(LocalDate day){
    System.out.println("@@@@@@@@@@@@@@@ made it into findByDay()");
    DateTime myDT = day.toDateTimeAtStartOfDay();
    Query query = this.em.createQuery("SELECT DISTINCT encounter FROM Encounter encounter WHERE encounter.dateTime LIKE :day");
    query.setParameter("day", myDT);
    return query.getResultList();       
}

这是 MySQL 中底层数据表的 sql:

CREATE TABLE IF NOT EXISTS encounters(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  patient_id int(11) UNSIGNED NOT NULL,
  office_id int(11) UNSIGNED NOT NULL,
  provider_id int(11) UNSIGNED NOT NULL,
  start_date TIMESTAMP,
  status varchar(50),
  FOREIGN KEY (patient_id) REFERENCES patients(id),
  FOREIGN KEY (office_id) REFERENCES facilityAddresses(id),
  FOREIGN KEY (provider_id) REFERENCES providers(id)
)engine=InnoDB;

这里是Encounter实体的相关部分:

@Entity
@Table(name = "encounters")
public class Encounter extends BaseEntity{

    @Column(name="start_date")
    private DateTime dateTime;

    //other mappings of columns to properties

    // getters and setters

}  

编辑:

这是我根据 Affe 的建议测试的内容:

@Override
public Collection<Encounter> findByDay(LocalDate day){
    System.out.println("kkkkkkkkkkkkkkkkkkkkkk inside repository.findByDay()  ");
    DateTime startDay = day.toDateTimeAtStartOfDay();
    DateTime startNextDay = startDay.plusDays(1);
    System.out.println("startDay is: "+startDay);
    System.out.println("startNextDay is: "+startNextDay);
    Query query = this.em.createQuery(
        "SELECT DISTINCT encounter " +
        "FROM Encounter encounter " +
        "WHERE encounter.dateTime >= :startDay and encounter.dateTime < :startNextDay");
    query.setParameter("startDay", startDay);
    query.setParameter("startNextDay", startNextDay);
    Collection<Encounter> myresult = query.getResultList();
    Object[] something = myresult.toArray();
    System.out.println("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv num results is: "+myresult.size());
    for(int i=0;i<something.length;i++){
        System.out.println("nnnnnnnnnnnnnnnnnnnnnnnnn "+something[i].toString());
    }
    return myresult;
}

这是将测试数据插入数据库的sql:

INSERT IGNORE INTO encounters VALUES (1, 5, 2, 1, '2013-11-30 09:00:00','Active');
INSERT IGNORE INTO encounters VALUES (2, 4, 1, 2, '2013-12-15 10:00:00','Inactive');
INSERT IGNORE INTO encounters VALUES (3, 3, 4, 3, '2014-1-10 11:00:00','Active');
INSERT IGNORE INTO encounters VALUES (4, 2, 3, 4, '2014-1-13 12:00:00','Inactive');
INSERT IGNORE INTO encounters VALUES (5, 1, 1, 3, '2014-1-12 13:00:00','Inactive');

当我选择2014-1-102014-1-132014-1-12 或其他插入的日期作为参数时,上面的system.out.println() 打印出结果数为零,因此 for 循环永远不会运行。查询应该为每一天返回一个结果。

例如,当我选择2014-1-10时,eclipse控制台输出如下:

kkkkkkkkkkkkkkkkkkkkkk inside repository.findByDay()  
startDay is: 2014-01-10T00:00:00.000-08:00
startNextDay is: 2014-01-11T00:00:00.000-08:00
Hibernate: select distinct encounter0_.id as id1_10_, encounter0_.start_date as start2_10_, encounter0_.office_id as office4_10_, encounter0_.patient_id as patient5_10_, encounter0_.status as status3_10_ from encounters encounter0_ where encounter0_.start_date>=? and encounter0_.start_date<?
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv num results is: 0
number of encounters is: 0
aaaa hours of day, mins of hour for block: 8, 0
aaaa hours of day, mins of hour for block: 9, 0
aaaa hours of day, mins of hour for block: 10, 0
aaaa hours of day, mins of hour for block: 11, 0
aaaa hours of day, mins of hour for block: 12, 0
aaaa hours of day, mins of hour for block: 13, 0
aaaa hours of day, mins of hour for block: 14, 0
aaaa hours of day, mins of hour for block: 15, 0
aaaa hours of day, mins of hour for block: 16, 0

System.out.println()输出的datetime的格式与问题有关系吗?我做错了什么?

【问题讨论】:

    标签: java spring hibernate spring-mvc jpa


    【解决方案1】:

    您需要在特定日期的所有时间戳范围内进行搜索。将时间戳视为数据库中的日期的功能是特定于 DB 的,不能通过 JPA API 获得。 (这通常是个坏主意,除非您基于日期值构建了功能索引。)

    @Override
    public Collection<Encounter> findByDay(LocalDate day){
        DateTime startDay = day.toDateTimeAtStartOfDay();
        DateTime startNextDay = startDay.plusDays(1);
        Query query = this.em.createQuery(
            "SELECT DISTINCT encounter " +
            "FROM Encounter encounter " +
            "WHERE encounter.dateTime >= :startDay and encounter.dateTime < :startNextDay");
        query.setParameter("startDay", startDay);
        query.setParameter("startNextDay", startNextDay);
        return query.getResultList();       
    }
    

    【讨论】:

    • 嗯,我实际上并没有太多使用hibernate + joda。你试过query.setParameter("startDay", startDay.toDate()); query.setParameter("startNextDay", startNextDay.toDate()); 吗?
    • 在您建议的位置添加 .toDate() 导致以下错误:Parameter value [Fri Jan 10 00:00:00 PST 2014] did not match expected type [org.joda.time.DateTime]; nested exception is java.lang.IllegalArgumentException: Parameter value [Fri Jan 10 00:00:00 PST 2014] did not match expected type [org.joda.time.DateTime]
    • 我还有一个相关的问题。你愿意帮我解决吗?这是新帖子的链接:stackoverflow.com/questions/22002272/…
    【解决方案2】:

    我认为问题在于日期格式

    您将日期以yyyy-MM-dd HH:mm:ss(即 2013-11-30 09:00:00) 格式存储在数据库中 并且您是 yyyy-MM-dd'T'HH:mm:ss (即 2014-01-10T00:00:00.000-08:00) 格式的 passig 日期查询

    首先你必须将你的 LocalDate 转换成给定的格式

    LocalDate localDate = new LocalDate(2010, 9, 14);
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    String startDay = formatter.print(localDate);
    

    那么你必须将它设置为查询参数

    Query query = this.em.createQuery(
        "SELECT DISTINCT encounter " +
        "FROM Encounter encounter " +
        "WHERE encounter.dateTime = "+ startDay +"");
    

    希望这能解决您的问题!

    【讨论】:

    • 您的方法导致以下运行时错误:java.lang.IllegalArgumentException: Parameter value [2014-02-10 00:00:00] did not match expected type [org.joda.time.DateTime]。错误定位在以下代码行:query.setParameter("startDay", startDay);您还有其他建议吗?
    • query.setParameter("startDay", startDay); 应该给你排序。
    【解决方案3】:

    问题的解决方案非常简单。我只需要将@Type 注释添加到Encounter 实体的dateTime 字段,如下所示:

    @Column(name="start_date")
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime dateTime;
    

    将这一行代码添加到实体后,我的原始 jpa/sql 代码可以正常工作。

    【讨论】:

    • 是的,您不需要查询范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多