#day 02-高级SQL, JDBC, SQL注入
##高级SQL
* 排序格式:
* 升序: `SELECT 列名1, 列名2 FROM 表名 ORDER BY 列名 (ASC默认 可不写);`
* 降序:: `SELECT 列名1, 列名2 FROM 表名 ORDER BY 列名 DESC;`
* 使用WHERE条件: `SELECT 列名1, 列名2 FROM 表名 WHERE 条件 ORDER BY 列名 ASC;`
* 注意: `WHERE`在前, `ORDER BY`在后, 否则报错
* 扩展:
* 排序可以按照多列, 如先按a列降序, 如果a列中有相同的值, 则按b列降序
* `SELECT * FROM table ORDER BY a DESC, b DESC;`
##聚合函数
* 作用:
* 对一列的值进行计算, 然后返回一个值.
* 格式: `SELECT 函数(列) FROM 表名 ...;`
* `COUNT(列名)`: 计算指定列的记录行数.
* 注意: 不会计算NULL值
* `SUM(列名)`: 计算指定列的数值总和
* 如果数据类型不是数值, 则结果为: 0
* `MAX(列名)`: 获取指定列的数值中的最大值
* `MIN(列名)`: 获取指定列的数值中的最小值
* `AVG(列名)`: 计算指定列的数值中的平均值
* 如果数据类型不是数值, 则结果为: 0
## 分组查询
* 分组查询
* `GROUP BY 列名 HAVING 条件`, 是`SELECT`的子句, 用于将查询出的结果归类分组显示
* 格式:
* `SELECT 列1, 列2 FROM 表名 [WHERE 条件] GROUP BY 列名 HAVING 条件;`
* `HAVING`关键字的作用: 对查询结果进行分组显示后, 再次按条件过滤
* 最终 sql语句
* `SELECT 列1,列2 FROM 表名 WHERE条件 GROUP BY 列名 HAVING 条件 ORDER BY 列名 DESC/ASC;`
* 注意:
* 分组查询中能使用的列名
* `HAVING`条件中的列名: 必须是`SELECT`条件或`GROUP BY`条件中使用过的列名
* `GROUP BY`后的列名: 可以使用表的所有字段
* 聚合函数与分组的使用效果
* 使用聚合函数后再进行分组, 才相当于汇总统计
* `SELECT zname, SUM(zmoney) FROM zhangwu GROUP BY zname;`
* 不使用聚合函数的分组, 只有第一条记录的值
* `SELECT zname, zmoney FROM zhangwu GROUP BY zname;`
* `HAVING`和`WHERE`的区别
* 过滤时机不同
* WHERE是在分组前对结果进行过滤
* HAVING是在分组后对结果进行再次过滤
* 是否可跟随聚合函数不同
* WHERE后不可使用聚合函数
* HAVING后可以使用聚合函数
* 条件可用字段不同
* HAVING条件中的字段必须是SELECT条件或GROUP BY条件中使用过的字段
* WHERE条件中可以使用表的所有字段
##JDBC
* JDBC就是一套API 可以通过Java代码来使用JDBC,提供了一套接口,
* 通过多态的方式调用数据库驱动中实现类的方法,对数据库进行操作
* 准备步骤
##1 注册驱动
* 告知JVM使用的是哪一个数据库驱动
* `Class.forName("com.mysql.jdbc.Driver");`
##2 获得连接
* 使用JDBC中的类完成对MySQL数据库的连接
* `Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybase","root","123456");`
* 获取Connection接口的实现类, 实现类是jar包中实现的
##3 获得语句执行平台(不建议使用)
* 通过连接对象获得对SQL语句的执行者对象
* `Statement cst = con.createStatement();`
* 获取Statement对象, 该对象用于将SQL语句发送到数据库
##3.1 使用PreparedStatement接口预编译SQL语句, 避免SQL注入
```
String sql = "UPDATE sort SET sname = ?,sprice = ? WHERE sid = ?";`用问号占位
PreparedStatement ps = con.prepareStatement(sql);`
ps.setObject(1, "汽车美容") 第几个问号 + 内容
ps.setObject(2, 34566);
ps.setObject(3, 2);
ps.executeUpdate();
```
##4 执行sql语句(执行INSERT语句, 获取结果集, 释放资源)
* `int rows = cst.executeUpdate(delete from sort where sname ='汽车用品');
* 执行SQL语句, 仅限于INSERT, DELETE, UPDATE, 返回生效的行数
##5 处理结果
* 执行SELECT语句, 获取结果集, 从结果集中获取数据
* `ResultSet rs = cst.executeQuery("SELECT * FROM sort");`
```
//执行sql语句
String sql= "select * from sort";
PreparedStatement ps = con.prepareStatement(sql);
//通过ps对象的方法执行查询语句
ResultSet resultSet = ps.executeQuery();
//遍历
while(resultSet.next()){
String string = resultSet.getString("sid")+"\t"
+resultSet.getString("sname")+"\t"
+resultSet.getString("sprice")+"\t"
+resultSet.getString("sdesc");
System.out.println(string);
}
```
## Statement类 && ResultSet接口 方法
```
*Statement类
ResultSet executeQuery(String sql): 执行SELECT查询, 返回查询结果到ResultSet对象中.
*ResultSet接口
boolean next()`: 将结果集的指针向下移动一行, 并返回是否还有下一条记录
注意: 没有调用该方法之前, ResultSet的光标在第一条记录之前, 只有调用一次next方法后, 指针才指向第一条记录
int getInt(int column): 获取第column列的int类型的数据
int getInt(String columnName): 获取指定列名的int类型的数据
String getString(int column): 获取第column列的String类型数据
String getString(String columnName): 获取指定列名的String类型的数据
Object getObject(String columnName): 获取指定列名的任何类型数据
void close()`: 释放结果集资源
```
##6 释放资源
* 一堆close();
##sql注入攻击
* SQL语句使用字符串拼接方式
* 使用Statement执行的语句
* 密码'1'or'1=1'(后面恒成立 true)
* `SELECT * FROM user WHERE username = '随便怎么写' AND password = '1' OR '1=1'`;
|
|