APIJSON 博客7 AbstractSQLConfig 第七篇

2021SC@SDUSC

我们来继续上周的分析

	@Override
	public String getSubqueryString(Subquery subquery) throws Exception {
		String range = subquery.getRange();
		SQLConfig cfg = subquery.getConfig();

		cfg.setPreparedValueList(new ArrayList<>());
		String sql = (range  == null || range.isEmpty() ? "" : range) + "(" + cfg.getSQL(isPrepared()) + ") ";

		preparedValueList.addAll(cfg.getPreparedValueList());

		return sql;
	}

这是对get子查询方法的定义

参数中的Subquery定义来自类Subquery中,用到的方法有

subquery.getRange()

subquery.getConfig()

所用方法在文件Subquery.java中定义如下

public class Subquery {
	
	private String path; // []/0/User
	private String originKey; //id{}@
	private JSONObject originValue; // { "from": "Comment", "Comment": {...} }

	private String from; // Comment
	private String range; // any, all
	private String key; //id{}
	private SQLConfig config;
	
	@JSONField(serialize = false) //解决泄漏 SQLConfig 里的 dbPassword 等
	public String getRange() {
		return range;
	}
	public void setRange(String range) {
		this.range = range;
	}
	@JSONField(serialize = false) //解决泄漏 SQLConfig 里的 dbPassword 等
	public SQLConfig getConfig() {
		return config;
	}
	public void setConfig(SQLConfig config) {
		this.config = config;
	}

	

这里是用了private保护了自己的变量

用调用方法返回变量

调用方法后建立String sql,对range和cfg拼接,返回SQL

知识学习

子查询就是将一个查询(子查询)的结果作为另一个查询(主查询)的数据来源或判断条件的查询。常见的子查询有WHERE子查询,HAVING子查询,FROM子查询,SELECT子查询,EXISTS子查询,子查询要使用小括号();

WHERE子查询

在WHERE子句中进行使用查询

SELECT *
FROM EMP
WHERE SAL < (SELECT AVG(SAL) FROM EMP);
  • 查询薪资比平均薪资低的员工信息

HAVING子查询

HAVING子句是对分组统计函数进行过滤的子句,也可以在HAVING子句中使用子查询

SELECT JOB,AVG(SAL)
FROM EMP
GROUP BY JOB
HAVING AVG(SAL) = (SELECT MAX(AVG(SAL)) FROM EMP GROUP BY JOB);
  • 查询平均薪资最高的职位及其平均薪资

FROM子查询

FROM子查询就是将一个查询结构(一般多行多列)作为主查询的数据源

SELECT JOB,AVG(SAL)
FROM (SELECT JOB,AVG(SAL) AS AVGSAL FROM EMP GROUP BY JOB)TEMP
WHERE TEMP.AVGSAL>2000;
  • 查询平均薪资高于2000的职位以及该职位的平均薪资

SELECT子查询

SELECT子查询在SELECT子句中使用查询的结果(一般会和dual空表一起使用)

SELECT (SELECT COUNT(*) FROM EMP WHERE JOB = 'SALESMAN')/(SELECT COUNT(*) FROM EMP)
FROM DUAL;
  • 职位是SALESMAN的员工占总员工的比例

EXISIT子查询

将主查询的数据带到子查询中验证,如果成功则返回true,否则发水false。主查询接收true是就会显示这条数据,flase就不会显示。

SELECT *
FROM EMP E
WHERE EXISIT (
	SELECT *
	FROM DEPT D
	WHERE E.DEPTNO = D.DEPTNO);

下面是拼接条件

	private static String getCondition(boolean not, String condition) {
		return not ? NOT + "(" + condition + ")" : condition;
	}

 参数是一个判断条件,和一个String 的 Condition

如果not——ture 返回 NOT+condition 如果not——false 返回condition

定义好后,后续会用到

	@NotNull
	public static JSONArray newJSONArray(Object obj) {
		JSONArray array = new JSONArray();
		if (obj != null) {
			if (obj instanceof Collection) {
				array.addAll((Collection<?>) obj);
			} else {
				array.add(obj);
			}
		}
		return array;
	}

传入的参数是Object 的obj

返回的是JSONArray 的array ,实现了向JSONArray的转变

方法内部如果obj为空则返回array,不为空则向array添加数据,最后返回array

JSONObject和JSONArray的数据表示形式

JSONObject的数据是用 { } 来表示的,

例如: { "id" : "123", "courseID" : "huangt-test", "title" : "提交作业", "content" : null }

而JSONArray,顾名思义是由JSONObject构成的数组,用 [ { } , { } , ...... , { } ] 来表示

例如: [ { "id" : "123", "courseID" : "huangt-test", "title" : "提交作业" } , { "content" : null, "beginTime" : 1398873600000 "endTime" } ] ;

表示了包含2个JSONObject的JSONArray。

可以看到一个很明显的区别,一个用的是 { } ,一个最外面用的是 [ ] ;

	@JSONField(serialize = false)
	public String getSetString() throws Exception {
		return getSetString(getMethod(), getContent(), ! isTest());
	}
	@JSONField(serialize = false)
	public String getSetString(RequestMethod method, Map<String, Object> content, boolean verifyName) throws Exception {
		Set<String> set = content == null ? null : content.keySet();
		String setString = "";

		if (set != null && set.size() > 0) {
			boolean isFirst = true;
			int keyType;// 0 - =; 1 - +, 2 - -
			Object value;

			String idKey = getIdKey();
			for (Entry<String,Object> entry : content.entrySet()) {
				String key = entry.getKey();
				//避免筛选到全部	value = key == null ? null : content.get(key);
				if (key == null || idKey.equals(key)) {
					continue;
				}

				if (key.endsWith("+")) {
					keyType = 1;
				} else if (key.endsWith("-")) {
					keyType = 2;
				} else {
					keyType = 0; //注意重置类型,不然不该加减的字段会跟着加减
				}
				value = entry.getValue();
				key = getRealKey(method, key, false, true, verifyName);

				setString += (isFirst ? "" : ", ") + (getKey(key) + " = " + (keyType == 1 ? getAddString(key, value) : (keyType == 2
						? getRemoveString(key, value) : getValue(value)) ) );

				isFirst = false;
			}
		}

		if (setString.isEmpty()) {
			throw new IllegalArgumentException("PUT 请求必须在Table内设置要修改的 key:value !");
		}
		return (isClickHouse()?" ":" SET ") + setString;
	}

 getSetString()直接返回了getSetString(getMethod(), getContent(), ! isTest())

getSetString(getMethod(), getContent(), ! isTest())定义在后面

对setstring进行累积,最后返回。

SQL SET 关键字使用方法及示例

SET命令与UPDATE一起使用,以指定应在表中更新哪些列和值。

下面的SQL使用新的联系人名和新的城市更新第一个客户(CustomerID = 1):

示例

 UPDATE Customers
 SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
 WHERE CustomerID = 1;

对于“国家/地区”为“Mexico”的所有记录,以下SQL会将字段"ContactName"更新为“ Juan”:

示例

UPDATE Customers
SET ContactName='Juan'
WHERE Country='Mexico';

注意:更新表中的记录时要小心!一定要注意UPDATE语句中的WHERE子句。WHERE子句指定应更新的记录。如果省略WHERE子句,表中的所有记录将被更新!

下面是getAddString()

	@JSONField(serialize = false)
	public String getAddString(String key, Object value) throws IllegalArgumentException {
		if (value instanceof Number) {
			return getKey(key) + " + " + value;
		}
		if (value instanceof String) {
			return SQL.concat(getKey(key), (String) getValue(value));
		}
		throw new IllegalArgumentException(key + "+ 对应的值 " + value + " 不是Number,String,Array中的任何一种!");
	}

getAddString(String key, Object value)参数是key 和 value

根据参数value的不同类型返回了两种结果

instanceof判断一个对象是否为一个类的实例

如果value是Number的实例则返回

getKey(key) + " + " + value

如果value是String的实例则返回

SQL.concat(getKey(key), (String) getValue(value))

这里用到了instanceof 

instanceof用法

instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

1

boolean result = obj instanceof Class

  其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

  注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

1、obj 必须为引用类型,不能是基本类型

1

2

3

int i = 0;

System.out.println(i instanceof Integer);//编译不通过

System.out.println(i instanceof Object);//编译不通过

  instanceof 运算符只能用作对象的判断。

2、obj 为 null

1

System.out.println(null instanceof Object);//false

  关于 null 类型的描述在官方文档:Chapter 4. Types, Values, and Variables 有一些介绍。一般我们知道Java分为两种数据类型,一种是基本数据类型,有八个分别是 byte  short  int  long  float  double  char boolean,一种是引用类型,包括类,接口,数组等等。而Java中还有一种特殊的 null 类型,该类型没有名字,所以不可能声明为 null 类型的变量或者转换为 null 类型,null 引用是 null 类型表达式唯一可能的值,null 引用也可以转换为任意引用类型。我们不需要对 null 类型有多深刻的了解,我们只需要知道 null 是可以成为任意引用类型的特殊符号

  在 JavaSE规范 中对 instanceof 运算符的规定就是:如果 obj 为 null,那么将返回 false。

3、obj 为 class 类的实例对象

1

2

Integer integer = new Integer(1);

System.out.println(integer instanceof  Integer);//true

  这是最普遍的一种用法。

4、obj 为 class 接口的实现类

  了解Java 集合的,我们知道集合中有个上层接口 List,其有个典型实现类 ArrayList

1

2

public class ArrayList<E> extends AbstractList<E>

        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  所以我们可以用 instanceof 运算符判断 某个对象是否是 List 接口的实现类,如果是返回 true,否则返回 false

1

2

ArrayList arrayList = new ArrayList();

System.out.println(arrayList instanceof List);//true

  或者反过来也是返回 true

1

2

List list = new ArrayList();

System.out.println(list instanceof ArrayList);//true

5、obj 为 class 类的直接或间接子类

  我们新建一个父类 Person.class,然后在创建它的一个子类 Man.class

1

2

3

public class Person {

}

  Man.class

1

2

3

public class Man extends Person{

     

}

  测试:

1

2

3

4

5

6

Person p1 = new Person();

Person p2 = new Man();

Man m1 = new Man();

System.out.println(p1 instanceof Man);//false

System.out.println(p2 instanceof Man);//true

System.out.println(m1 instanceof Man);//true

  注意第一种情况, p1 instanceof Man ,Man 是 Person 的子类,Person 不是 Man 的子类,所以返回结果为 false。

 2604

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值