前言
很多人跟小编吐槽,在了解MySQL的高级特性之后,比如架构设计、备份与复制、分析查询、智能监控、故障处理等等,对SQL语句的编写还是比较难上手!
对编写稍微复杂的SQL查询就比较心虚,这样的童鞋肯定不占少数!
从开发的角度来讲,数据库只是为程序存储数据,不需数据库来进行任何复杂计算,如果利用数据库进行复杂计算,这样会非常影响数据库的性能。
但是对于其他职业,例如BI工程、测试工程师、ETL工程师、还有近几年的新兴职业:叫什么数据工程师,会玩数据,处理数据,对数据非常感兴趣,鼻子非常灵敏的职业:统称数据工程师!
如果老板要数据非常急,我们利用BI工具,ETL工具,甚至编写java代码、C代码、甚至比较简洁的Python代码,这都是从思想上不对的!
如果您的一定规模的数据是存储在数据库中:
小编的建议是:能尽量SQL就SQL,不能SQL,就BI,BI不行就ETL上。ETL不行在写代码!
(如果有比较急、和实时性比价高的数据报表请求,一定要在读权重非常低的从库上进行! )
我给大家总结一个道理:在数据最近的地方处理数据,是最省成本、最省时间的的最佳方案。
下面使用案例中的表结构
dept
create table dept(deptno int primary key, dname varchar(30),loc varchar(30))engine=InnoDB;
insert into dept values(10,'accounting','new york');
insert into dept values(20,'research','dallas');
insert into dept values(30,'sales','chicago');
insert into dept values(40,'operations','boston');
emp
create table emp(empno int primary key,ename varchar(30),job varchar(30),mgr int, hiredate datetime, sal numeric(10,2), comm numeric(10,2), deptno int, foreign key (deptno) references dept(deptno) on delete cascade)engine=innoDB;
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values (7934,'miller','clerk',7782,'1982-1-23',1300.00,10);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values (7902,'ford','analyst',7566,'1981-12-3',3000.00,20);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values (7900,'james','clerk',7698,'1981-12-3',950.00,30);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values (7876,'adams','clerk',7788,'1987-5-23',1100.00,20);
insert into emp values (7844,'turner','salsman',7698,'1982-9-8',1500.00,0.00,30);
insert into emp(empno,ename,job,hiredate,sal,deptno) values (7839,'king','president','1981-11-17',5000.00,10);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values(7788,'scott','analyst',7566,'1987-4-19',3000.00,20);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values (7782,'clark','manager',7839,'1981-6-9',2450.00,10);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values(7698,'blake','manager',7839,'1981-5-1',2850.00,30);
insert into emp values (7654,'martin','salsman',7698,'1981-9-28',1250.00,1400.00,30);
insert into emp(empno,ename,job,mgr,hiredate,sal,deptno) values(7566,'jones','manager',7839,'1981-4-2',2975.00,20);
insert into emp values(7521,'ward','salesman',7698,'1981-2-22',1250.00,500.00,30);
insert into emp values (7499,'allen','salseman',7698,'1981-2-20',1600.00,300.00,30);
insert into emp (empno,ename,job,mgr,hiredate,sal,deptno) values(7369,'smith','clerk',7902,'1980-12-27',800.00,20);
一、多条件查询
1、使用WHERE子句和OR和子句。例如,如果你想找部门(10)的所有员工,以及任何获得佣金的员工,以及部门20中工资不超过2000美元的员工。
1 select *
2 from emp
3 where deptno = 10
4 or comm is not null
5 or sal <= 2000 and deptno=20
解说:WHERE 子句查找满足下列条件的数据行:DEPTNO是10,或 COMM为NULL或DEPTNO 为20的工资为2000美元以下的员工。
2、 连接列值
select ename, job from emp where deptno = 10
ENAME JOB
--------- ---------
CLARK MANAGER
KING PRESIDENT
MILLER CLERK
mysql concat(str1,str2,...)
返回结果为连接参数产生的字符串,如果任何一个参数带有null,则返回结果为null.如果所有参数均为非二进制字符串,则结果为非二进制字符串。 如果自变量中含有任一二进制字符串,则结果为一个二进制字符串。
一个数字参数被转化为与之相等的二进制字符串格式;若要避免这种情况,可使用显式类型 cast, 例如: SELECT CONCAT(CAST(int_col AS CHAR), char_col);
select concat(ename, ' WORKS AS A ',job ) as msg from emp where deptno =10;
+---------------------------+
| msg |
+---------------------------+
| CLARK WORKS AS A MANAGER |
| KING WORKS AS A PRESIDENT |
| MILLER WORKS AS A CLERK |
+---------------------------+
3 rows in set
3、多结果集进行if-else操作。
您希望在SELECT语句中对值执行if-else操作。例如,您希望生成一个结果集,如果员工的工资为2000美元或更少,则返回“低工资”的消息,如果员工的工资是4000美元或更多,则返回一个“多付”的信息,如果他们在两者之间工资,则返回“OK”。结果集应该是这样的:
1 select ename,sal,
2 case when sal <= 2000 then 'UNDERPAID'
3 when sal >= 4000 then 'OVERPAID'
4 else 'OK'
5 end as status
6 from emp
ENAME SAL STATUS
---------- ---------- ---------
SMITH 800 UNDERPAID
ALLEN 1600 UNDERPAID
WARD 1250 UNDERPAID
JONES 2975 OK
MARTIN 1250 UNDERPAID
BLAKE 2850 OK
CLARK 2450 OK
SCOTT 3000 OK
KING 5000 OVERPAID
TURNER 1500 UNDERPAID
ADAMS 1100 UNDERPAID
JAMES 950 UNDERPAID
FORD 3000 OK
MILLER 1300 UNDERPAID
4、空值处理
查找空值
|
将空值转换为实际值
(只要comm非空就返回comm的值,否则返回0)
1 select coalesce(comm,0)
2 from emp 5、按模式搜索
在部门10和20中需要返回一个名字中带I 或者职位中带“ER”的员工。
|
1 select ename, job
2 from emp
3 where deptno in (10,20)
4 and (ename like '%I%' or job like '%ER')
6、排序
您要排序EMP的行首先由DEPTNO升序,然后按薪水降序排序。 您要返回以下结果集:
ORDER BY子句中不同的排序列,用逗号分隔:
|
您想按字符串的特定部分对查询的结果进行排序。
例如,要从表EMP返回员工名称和作业,并按作业字段中最后两个字符进行排序。 结果集应如下所示:
|
如果对排序感兴趣的可以自行查阅:mysql的校队规则等!
6.1、对字母和数字混合的数据排序
1、首先创建个视图
create view V
as
select concat(ename,' ',deptno) as data
from emp
select * from V
DATA
-------------
SMITH 20
ALLEN 30
WARD 30
JONES 20
MARTIN 30
BLAKE 30
CLARK 10
SCOTT 20
KING 10
TURNER 30
ADAMS 20
JAMES 30
FORD 20
MILLER 10
2、进行排序
|
上述是Oracle的排序方案!
mysql中还没特别好的方案,有一些BI工具把一个字段拆分成两个字段,然后在进行排序!
如果是单个varchar字段里面是数值,可以通过下方案例。
今天遇到一个问题,就是对mysql数值字符串类型进行排序,在默认情况下使用order by 字段名称 desc/asc 进行排序的时候,mysql进行的排序规则是按照ASCII码进行排序的,并不会自动的识别出这些数据是数值,百度了一下,发现对于这种情况,可以采用
order by 字段名称+0 desc/asc的形式进行排序(亲测有效)
order by 字段名称*1 desc/asc的形式进行排序( 没有进行测试 )
这样mysql会将数值字符串类型的数据当作数值进行处理,但是存在效率问题,不推荐使用varchar/char类型来存储数值,这样会带来不不必要的问题。
6.2 处理排序空值
您想通过COMM对EMP的结果进行排序,但该字段为空。 您需要一种方式来指定是否为最后排序null:
当值为NULL时,使用CASE表达式来“标记”。
这个想法是拥有一个带有两个值的标志:一个表示NULL,另一个表示非NULL。 一旦这样做,只需将该标志列添加到ORDER BY子句。 您可以轻松地控制NULL值是先排序还是最后排序,而不会影响非NULL值:
|
6.3、条件排序
你想根据一些条件逻辑进行排序。 例如:如果JOB是“SALESMAN”,你想对COMM进行排序; 否则,您想按SAL排序。 您要返回以下结果集:
select ename,sal,job,comm
from emp
order by case when job LIKE 'sal%' then comm else sal end
二、多表操作
2.1、例如,要在表EMP中显示部门10中的员工的姓名和部门编号,以及表DEPT中每个部门的名称和部门编号。 您希望结果集如下所示:
|
2.2 查找两个表中的共同行
您希望返回与视图V中的行匹配的EMP中所有员工的EMPNO,ENAME,JOB,SAL和DEPTNO。
两种方法:
第一种:
第二种:
结果
2.3 从一个表中查找另一个表中没有的值
从dept的deptno中查找emp表中不存在的值:
如果 deptno字段有空值。则返回结果中就会为空的记录。
如果要解决 使用IN 的逻辑的语法并且与null相关联出现的异常:可以用 not exists 来代替,解决表中有空值的问题!
2.4 从一个表中查找与其他表不匹配的记录
2.5、向查询中增加联接而不影响其他链接
您有一个查询返回您想要的结果。您需要其他信息,但是当尝试获取它时,您将从原始结果集中丢失数据。
例如,您要返回所有员工,他们工作的部门的位置以及他们收到奖金的日期。对于此问题,EMP_BONUS表包含以下数据:
您开始的查询如下所示:
您想向这些结果添加奖金给员工的日期,但是加入EMP_BONUS表会返回更少的行数,因为并不是每个员工都有一个奖金:
您想要的结果集如下:
您可以使用外连接获取附加信息,而不会丢失原始查询中的数据。首先连接表EMP到表DEPT以获得所有员工和他们工作的部门的位置,然后外部加入表EMP_ BONUS返回奖金的日期,如果有的话.
您还可以使用标量子查询(位于SELECT列表中的子查询)来模拟外连接:
2.5、检测两个表中是否有相同的值。
查找方案:
在E中找出V中没有的行: :
首先,在表EMP中查找视图不存在的行。
然后将这些行与表EMP中不存在的视图V中的行结合(UNION ALL)
在V中找出E中没有的行:
|