package org.easyframe.tutorial.lesson3;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import jef.codegen.EntityEnhancer;
import jef.common.log.LogUtil;
import jef.database.Condition.Operator;
import jef.database.DbClient;
import jef.database.DbClientBuilder;
import jef.database.ORMConfig;
import jef.database.QB;
import jef.database.query.Func;
import jef.database.query.Join;
import jef.database.query.Query;
import jef.database.query.QueryBuilder;
import jef.database.query.Selects;
import jef.http.client.support.CommentEntry;
import jef.tools.string.RandomData;
import org.easyframe.tutorial.lesson2.entity.Student;
import org.easyframe.tutorial.lesson2.entity.StudentToLesson;
import org.junit.Test;
/**
* 之前看了查询条件的用法。现在看看更多灵活的查询用法。
* @author geequery
*
*/
public class Case2 extends org.junit.Assert {
DbClient db;
public Case2() throws SQLException {
db = new DbClientBuilder().setEnhancePackages("org.easyframe.tutorial").build();
// 准备数据时关闭调试,减少控制台信息
ORMConfig.getInstance().setDebugMode(true);
db.dropTable(Student.class, StudentToLesson.class);
db.createTable(Student.class, StudentToLesson.class);
prepareData(15);
ORMConfig.getInstance().setDebugMode(true);
}
/**
* 使用selectFrom方法,来指定要查询的字段 。未指定要查询的字段不会被查出。
* @throws SQLException
*/
@Test
public void testSelect_selectFrom() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
query.addCondition(QueryBuilder.eq(Student.Field.gender, "F"));
//指定:仅查询id,name两个字段
Selects selects = QueryBuilder.selectFrom(query);
selects.column(Student.Field.id);
selects.column(Student.Field.name);
List<Student> students = db.select(query);
// 验证数据
if (students.size() > 0) {
Student st = students.get(0);
assertNotNull(st.getName());
assertNull(st.getGender());
}
}
/**
* 查出所有学生姓名,使用distinct语句过滤掉重复的。
*
* @throws SQLException
*/
@Test
public void testSelect_selectDistinct() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
Selects selects = QueryBuilder.selectFrom(query);
selects.setDistinct(true);
selects.column(Student.Field.name);
// 相当于 select distinct t.NAME from STUDENT t
List<Student> students = db.select(query);
}
/**
* group by的查询该怎么用?
* 下面的例子演示了将学生按照男生、女生分组进行统计。
*
* @throws SQLException
*/
@Test
public void testSelect_selectGroup() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
Selects selects = QueryBuilder.selectFrom(query);
selects.column(Student.Field.gender).group(); // 按性别分组
selects.column(Student.Field.id).count(); // 统计人数
selects.column(Student.Field.id).max(); // 最大的学号
selects.column(Student.Field.id).min(); // 最小的学号
// 上述查询的结果。无法再转换为Student对象返回了,这里将各个列按顺序形成数组返回。
List<String[]> stat = db.selectAs(query, String[].class);
for (Object[] result : stat) {
System.out.print("M".equals(result[0]) ? "男生" : "女生");
System.out.print(" 总数:" + result[1] + " 最大学号:" + result[2] + " 最小学号" + result[3]);
System.out.println();
}
}
/**
* 带有Having子句的查询该怎么使用?
* 我们对学生按年级进行分组统计,同时使用having子句过滤掉人数大于2的年级。
*
* @throws SQLException
*/
@Test
public void testSelect_groupHaving() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
Selects selects = QueryBuilder.selectFrom(query);
selects.column(Student.Field.grade).group(); // 按年级分组
selects.column(Student.Field.grade).count().having(Operator.GREAT, 2); // 查出人数,同时添加一个Having条件,count(id)>2
List<String[]> stat = db.selectAs(query, String[].class);
for (Object[] result : stat) {
System.out.print("年级:" + result[0] + " 人数:" + result[1]);
System.out.println();
}
}
/**
* 查询学生数量的语句中,使用distinct……
* @throws SQLException
*/
@Test
public void testSelect_countDistinct() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects items = QB.selectFrom(q);
items.column(Student.Field.name);
items.setDistinct(true);
//q.setMaxResult(1);
long total = db.count(q);// 取总数
List<String> result=db.selectAs(q,String.class);
System.out.println("总数为:"+ total +" 查出"+ result.size()+"条");
}
/**
* 查询学生数量的语句中,使用distinct——的另一种写法
*/
@Test
public void testSelect_countDistinct2() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects items = QB.selectFrom(q);
items.column(Student.Field.name).countDistinct();
Integer total=db.loadAs(q,Integer.class);
System.out.println("Count:"+ total);
}
/**
* 分组查询 group by以后,常用的统计函数——
* @throws SQLException
*/
@Test
public void testSelect_function1() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects items = QB.selectFrom(q);
items.column(Student.Field.id).min().as("min_id");
items.column(Student.Field.id).max().as("max_id");
items.column(Student.Field.id).sum().as("sub_id");
items.column(Student.Field.id).avg().as("avg_id");
for(Map<String,Object> result:db.selectAs(q,Map.class)){
System.out.println(result);
}
}
/**
* 在查询中,除了常用统计函数,还可以使用标准的系统函数,这些系统函数几乎囊括了大部分数据库上的常用函数。
* 例如下面的 decode函数和upper函数。
*
* @throws SQLException
*/
@Test
public void testSelect_function2() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects items = QB.selectFrom(q);
//对姓名统一转大写
items.column(Student.Field.name).func(Func.upper);
//性别进行函数转换,decode是Oracle下的函数,注意观察其在Derby下的处理。有兴趣的可以换成MySQL试一下。
items.column(Student.Field.gender).func(Func.decode, "?", "'M'" ,"'男'","'F'" ,"'女'");
//先对日期转文本,然后截取前面的部分
items.column(Student.Field.dateOfBirth).func(Func.str).func(Func.substring,"?","1","10");
for(String[] result:db.selectAs(q,String[].class)){
System.out.println(Arrays.toString(result));
}
}
/**
* 当然如果不愿意用API编写select 部分的,直接写SQL 片段也是允许的。
*
* 下面的例子直接用SQL片段来描述查询的内容。同时对片段也是支持各种数据库兼容的。(用到了SQL改写技术)
* @throws SQLException
*/
@Test
public void testSelect_sqlExpression() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects select = QB.selectFrom(q);
select.columns("name,decode(gender,'F','女','M','男') as gender");;
for(Student result:db.select(q)){
System.out.println(result.getName()+" "+result.getGender());
}
}
/**
* 同样的日期时间也有相关的标准函数支持。
* @throws SQLException
*/
@Test
public void testSelect_sqlExpression2() throws SQLException {
Query<Student> q = QB.create(Student.class);
Selects select = QB.selectFrom(q);
select.column(Student.Field.name);
select.sqlExpression("str(add_months(Date_Of_Birth,24))").as("BIRTH_ADD_24");
for(String[] result:db.selectAs(q,String[].class)){
System.out.println(Arrays.toString(result));
}
}
/**
* 在自定义Join以后,也可以进行count distinct操作。
* @throws SQLException
*/
@Test
public void testSelect_JoinCountDistinct() throws SQLException {
Query<Student> q = QB.create(Student.class);
Query<StudentToLesson> q2 = QB.create(StudentToLesson.class);
Join join = QueryBuilder.innerJoin(q, q2, QB.on(Student.Field.id, StudentToLesson.Field.studentId));
Selects items = QB.selectFrom(join);
items.noColums(q2);
items.column(Student.Field.name);
items.setDistinct(true);
join.setMaxResult(1);
long total = db.count(join);// 取总数
System.out.println("总数" + total);
LogUtil.show(db.selectAs(join, String.class)); // 查询,由于总数被限制为1,因此只会显示第一条。
}
/**
* 自定义列的别名,然后用自定义对象容器作为返回结果
* @throws SQLException
*/
@Test
public void testSelect_selectCustome() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
Selects selects = QueryBuilder.selectFrom(query);
ORMConfig.getInstance().setFormatSQL(false);
selects.column(Student.Field.id).as("key");
selects.column(Student.Field.name).as("value");
List<CommentEntry> stat = db.selectAs(query, jef.http.client.support.CommentEntry.class);
System.out.println(stat);
}
/**
* 自定义Join,每条记录映射为多个对象
* @throws SQLException
*/
@Test
public void testSelect_selectMulti() throws SQLException {
Query<Student> query = QueryBuilder.create(Student.class);
Join join = QB.innerJoin(query, QB.create(StudentToLesson.class), QB.on(Student.Field.id, StudentToLesson.Field.studentId));
List<Object[]> results = db.selectAs(join, Object[].class);
for (Object[] result : results) {
Student st = (Student) result[0];
StudentToLesson sl = (StudentToLesson) result[1];
System.out.println(st + " - " + sl);
}
}
private void prepareData(int num) throws SQLException {
List<Student> data = new ArrayList<Student>();
Date old = new Date(System.currentTimeMillis() - 864000000000L);
for (int i = 0; i < num; i++) {
// 用随机数生成一些学生信息
Student st = new Student();
st.setGender(i % 2 == 0 ? "M" : "F");
st.setName(RandomData.randomChineseName());
st.setDateOfBirth(RandomData.randomDate(old, new Date()));
st.setGrade(String.valueOf(RandomData.randomInteger(1, 6)));
data.add(st);
}
db.batchInsert(data);
List<StudentToLesson> data2 = new ArrayList<StudentToLesson>();
for (int i = 0; i < num; i++) {
StudentToLesson sl = new StudentToLesson();
sl.setStudentId(data.get(i).getId());
sl.setLessionId(100);
data2.add(sl);
}
db.batchInsert(data2);
}
}