我正在为餐馆数据库程序创建一个JDBC,用户可以看到过去7天内的利润报告。
我不知道如何选择过去七天,所以该计划显示七天前的总利润。
我想知道如何实现这一点,我的代码看起来像这样:
public static void showSevenDaysAgoSells() {
double value = 0.0;
try {
System.out.println("----Showing last seven days profit----");
PreparedStatement stmt = conn.prepareStatement("SELECT sum(total) FROM sells WHERE date > date_from_7_days_ago");
java.sql.Date date= new java.sql.Date(new java.util.Date().getTime());
stmt.setObject(1, LocalDate.now(ZoneId.of("America/Caracas")).minusWeeks(1));
stmt.executeQuery();
ResultSet rs = stmt.executeQuery();
rs.next();
String sum = rs.getString(1);
value = Double.parseDouble(sum);
System.out.println("DAYS" + "\t" + "TOTAL");
System.out.println(date+ "\t" + sum);
} catch(Exception e) {
e.printStackTrace();
}
}
答案 0 :(得分:3)
PreparedStatement stmt = conn.prepareStatement(
"SELECT sum( total_ ) FROM sells_ WHERE date_ > ? ;"
);
...和...
stmt.setObject( // Use JDBC 4.2 method for passing/fetching java.time types.
1 , // Specify which placeholder `?` in PreparedStatement (1, 2, 3, etc.). In this case, `1`.
LocalDate.now( // Get current date (today) in desired/expected time zone.
ZoneId.of( "America/Montreal" )
).minusWeeks( 1 ) // Go back in time a week (7 days).
)
?
您在SQL字符串中嵌入了变量date_from_7_days_ago
。因此它被视为字符串文字,而不是Java变量的传递值。将该变量名称替换为PreparedStatement
的问号?
占位符。
PreparedStatement stmt = conn.prepareStatement( "SELECT sum( total_ ) FROM sells_ WHERE date_ > ? ;" );
提示:避免使用date
和total
等保留字来命名列和其他数据库标识符。各种SQL数据库总共保留了超过一千个保留字,因此碰撞比人们意识到的要容易。 SQL规范明确承诺永远不会保留带尾随下划线的任何单词。因此,请将您的所有标识符date_
,total_
命名为永远不要担心冲突。
问题和其他答案都使用了经过证明设计不当,容易混淆和有缺陷的麻烦的旧日期时间类。它们现在已经遗留下来,取而代之的是java.time类。
java.time.LocalDate
类表示没有时间且没有时区的仅限日期的值。
问题和其他答案都忽略了时区的关键问题。
确定日期时需要时区。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
如果您的业务逻辑要求指的是UTC而不是特定时区,请使用常量ZoneOffset.UTC
。
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
要获得七天前(一周),请让对象执行date-math。
LocalDate weekAgo = LocalDate.minusWeeks( 1 );
如果JDBC driver符合JDBC 4.2及更高版本,则可以通过PreparedStatement.setObject
和ResultSet.getObject
直接使用java.time类型。
myPreparedStatement.setObject( … , weekAgo );
并检索:
LocalDate ld = myResultSet.getObject( … , LocalDate.class );
至少这两个Postgres的JDBC驱动程序可能已经针对JDBC 4.2进行了更新,尽管我还没有测试它们是否支持java.time类型。
如果您的JDBC驱动程序不符合,那么请回到使用java.sql。但是尽可能简短地这样做,立即转换为/从java.time转换。要转换,请查看添加到旧类的新方法。在这种情况下,我们必须使用valueOf
和toLocalDate
方法回归使用java.sql.Date
。
myPreparedStatement.setObject( … , java.sql.Date.valueOf( weekAgo ) );
并检索:
LocalDate ld = myResultSet.getDate( … ).toLocalDate() ;
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:-1)
待办事项
final long OneDayMillis = 86400000l;
PreparedStatement stmt = conn.prepareStatement("SELECT sum(total) FROM sells WHERE date > ?");
java.sql.Date date = new java.sql.Date(System.currentTimeMillis()-OneDayMillis*7l);
stmt.setDate(1, date);
考虑到服务器的当前日期可能与客户端计算机的当前日期不同,因此最好将服务器端日期与SQL语句一起使用,如
SELECT sum(total) FROM sells WHERE date > current_date - integer '7'
没有任何来自客户端的参数绑定。