1 #开启关闭服务 2 #管理员启动cmd,,net start/stop mysql,, 3 #登录数据库,,mysql 【-h localhost -P 端口号】 -u 用户名 -p,, 4 #退出数据库,,exit,, / #ctrl+c 5 #查看版本号,,mysql -V,, 6 ##常见语句 7 #查看当前所有数据库 8 SHOW DATABASES; 9 #打开指定的库,,use 库名; 10 #查看某库所有的表,,show tables; // show tables from 库名; 11 /*创建表,, create table( 12 字段名称 字段类型, 13 字段名称 字段类型 14 );*/ 15 #查看表结构,,desc 表名; 16 #修改字符集 set names gbk; 17 #查看表内容,,select * from 表名; 18 #插入内容,,insert into 表名 (id , name) values (1,‘yangbo’); 19 #更新修改内容,,update 表名 set name='yb' where id=1; 20 #删除内容,,delete from 表名 where id=1; 21 ##不区分大小写 22 ##单行注释 #注释 -- 注释 23 ##多行注释 /* 注释 */ 24 ###data query language/ data manipulation lan/ 25 ### data define lan/transcation control lan/ 26 ###DQL数据查询语言 27 ##进阶1 基础查询----------------------------------------- 28 # select (字段、常量、表达式、函数) from 表名; 29 USE myemployees; 30 SELECT 31 job_id #F12变规范 32 FROM 33 jobs; 34 35 SELECT 36 `manager_id`, #`` 区分系统sql关键字和字段名 37 `first_name`, 38 #逗号自己加 39 `email` 40 FROM 41 `employees`; 42 43 SELECT * FROM employees; 44 45 SELECT 1+4; 46 47 #查询函数 48 SELECT VERSION(); 49 50 #起别名alias 便于理解 ,防止重名 51 SELECT last_name AS 姓 , first_name AS 名 FROM employees; 52 SELECT last_name 姓 FROM employees ; # 无AS 53 SELECT last_name 'x #i ng' FROM employees; 54 55 #去重 56 SELECT DISTINCT department_id FROM employees; 57 58 # + 号的作用 59 SELECT 10+10; #==20 60 SELECT "10"+10; #==20 61 SELECT '1o'+10; #==11 62 SELECT 'oo'+10; #==10 63 SELECT NULL+10; #==null 64 65 #拼接文本,判断是否为null 66 SELECT CONCAT(last_name,first_name) AS 姓名 FROM employees; 67 SELECT CONCAT(`first_name`,`job_id`,IFNULL(`commission_pct`,0)) AS infor 68 FROM employees; 69 70 ##进阶2 条件查询-------------------------------------------- 71 /* 72 select 查询列表 #3 73 from 表名 #1 74 where 条件 #2 75 76 条件表达 < > = != <> <= >= 77 #逻辑表达 && || ! 连接多条件表达 78 # and or not 79 #模糊查询 80 like 81 between and 82 in 83 is null 84 */ 85 USE `myemployees`; 86 87 SELECT 88 * 89 FROM 90 employees 91 WHERE salary > 12000; 92 93 94 95 SELECT 96 last_name, 97 `department_id` 98 FROM 99 `employees` 100 WHERE `department_id` <> 90; 101 102 103 SELECT 104 last_name, 105 salary 106 FROM 107 employees 108 WHERE 109 salary>=10000 AND salary<=20000; 110 111 #查询部门编号不是在90-120,或者工资大于15000的员工信息 112 SELECT * 113 FROM employees 114 #where not(`department_id`>=90 and `department_id`<=120) or salary>15000; 115 #where department_id not between 90 and 15000 or salary>15000; 116 WHERE NOT(department_id BETWEEN 90 AND 15000) OR salary>15000; 117 118 119 #模糊查询 通配符 120 # % 表示任意多个字符 _ 表示1个字符 , %%不能代表null!!!!!!!!!! 121 SELECT * 122 FROM employees 123 WHERE last_name LIKE '%a%'; #姓包含a 124 SELECT * 125 FROM employees 126 WHERE last_name LIKE '_i%'; #查询第二个字符为i,注意%的使用 127 SELECT * 128 FROM `employees` 129 WHERE last_name LIKE '_\_%'; #查询第二个字符为下划线。\为转义符 130 SELECT * 131 FROM employees 132 WHERE last_name LIKE '_$_%' ESCAPE '$'; #escape指定转义符为$ 133 134 #between A and B === >=A and <=B,所以 A<=B 135 SELECT * 136 FROM employees 137 WHERE `employee_id` BETWEEN 100 AND 120; 138 139 #in 140 /* 141 in === multiple or , 不支持通配符,因为or是=,不是like 142 */ 143 SELECT * 144 FROM employees 145 WHERE `job_id` IN ('AD_VP','IT_PROG'); 146 # where `job_id`='AD_VP' OR `job_id`='IT_PROG'; 147 148 149 #is null / is not null 150 SELECT * 151 FROM employees 152 WHERE commission_pct IS NULL; 153 154 SELECT ISNULL(`commission_pct`),commission_pct #判断为null=1,notnull=0 155 FROM `employees`; 156 157 #安全等于 <=> 158 SELECT * 159 FROM employees 160 WHERE `job_id` <=> 'AD_VP'; 161 162 SELECT * 163 FROM employees 164 WHERE salary <=> 12000; 165 166 SELECT * 167 FROM employees 168 WHERE commission_pct <=> NULL; 169 170 171 ##进阶3 排序--------------------------------------------- 172 173 #ORDER BY 默认asc ,降序,放在查询最后(除limit之外) 174 #工资从高到低 175 SELECT * FROM `employees` ORDER BY salary DESC; 176 177 #加筛选条件 178 #按表达式排序 179 #ifnull(字段,0),字段值为null,赋值为0,不为null,为原值 180 SELECT salary, salary*12*(1+IFNULL(`commission_pct`,0)) AS 年薪 181 FROM employees 182 ORDER BY salary*12*(1+IFNULL(`commission_pct`,0)); 183 184 #按照别名排序 185 SELECT salary, salary*12*(1+IFNULL(`commission_pct`,0)) AS 年薪 186 FROM employees 187 ORDER BY 年薪 DESC; #说明order by 最后一步执行 188 189 #按函数排序 190 SELECT `last_name`,LENGTH(`last_name`) 191 FROM `employees` 192 ORDER BY LENGTH(`last_name`) DESC; 193 194 #多条件排序 员工信息 先按工资升序,后按 员工编号降序 195 SELECT * 196 FROM employees 197 ORDER BY salary ASC,`employee_id` DESC; 198 199 200 ##进阶4 常见函数------------------------------------------------- 201 202 /* 203 函数分为单行和多行函数 204 单行比如length(),肯定有返回值 205 1.字符函数(处理字符串) 206 多行函数,又称组函数,统计用 207 */ 208 209 #一、 字符函数########################## 210 211 #1.length,获取字符长度 212 SELECT LENGTH('莫默123aaa'); 213 #UTF8中文为3个字节,GBK中文2个字节 214 SHOW VARIABLES LIKE '%char%'; 215 216 #2.concat 217 SELECT CONCAT(`last_name`,'_',`first_name`) AS 姓名 FROM employees; 218 219 #3.upper lower 220 221 SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees; 222 223 #4.substr / substring 224 SELECT SUBSTR('李莫愁爱上了陆展元',7) AS output; #从第7个位置开始 225 SELECT SUBSTR('李莫愁爱上了陆展元',1,3) AS output; #从第1个位置开始的三个字符 226 227 #大写首字母 228 SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),LOWER(SUBSTR(last_name,2))) 229 FROM employees; 230 231 #5 instr 232 #返回substr在str中第一次出现的索引,若不匹配,返回0 233 SELECT INSTR('杨不悔爱上了殷六侠','殷六侠') AS output; 234 #substr和instr连用,取邮箱用户名 235 SELECT SUBSTR(email,1,INSTR(email,'@')-1) FROM ..; 236 #6. trim 237 #去掉首位空格或指定str 238 SELECT TRIM(' 莫默 ') AS output; 239 SELECT TRIM('a' FROM 'aa默aa') AS output; 240 241 #7. lpad 242 #左填充str为10个字符长,用padstr填充 243 SELECT LPAD('莫默',10,'*') AS output; 244 245 #8. rpad 246 SELECT RPAD('y',5,'-') AS output; 247 248 #9 replace 249 # 在str中,from_str被to_str替代 250 SELECT REPLACE('张无忌爱上了周芷若','周芷若','赵敏') AS output; 251 252 #二、数学函数############################ 253 254 SELECT ROUND(1.4); 255 SELECT ROUND(1.459,2); 256 257 SELECT CEIL(1.01); # 取右 取≥该参数的最小整数 258 259 SELECT FLOOR(-1.09); #往数轴 取左 260 261 SELECT TRUNCATE(1.123456,4); #取小数点前4位 262 263 #取余 264 SELECT MOD(10,3); 265 SELECT MOD(-10,3); #结果和被除数正负一致 266 SELECT 10%3; 267 268 #出一个随机数,范围0-1 269 SELECT RAND(0123456); 270 #三、日期函数############################## 271 SELECT NOW(); 272 273 SELECT CURDATE(); 274 275 276 SELECT CURTIME(); 277 #获得指定的部分 year年 month月 date日 hour小时 minute分 second秒 278 SELECT YEAR(NOW()); 279 SELECT YEAR('1994-09-10'); 280 SELECT YEAR(hiredate) FROM employees; 281 SELECT MONTH(NOW()); 282 SELECT MONTHNAME(NOW()); #返回英文月 283 284 #日期格式的字符 转换成指定的格式 285 #%Y1994 %y94 %m01 %c1 %d30 %H24 %h12 %i00 59 %s00 59 286 SELECT MONTHNAME( STR_TO_DATE('1994-4-2','%Y-%c-%d') )output ; 287 # 日期型字符 该字符的格式 288 /* 289 #查询入职日期为1992-4-3的员工信息 290 select * from employees where hiredate = '1992-4-3'; 291 若日期型字符格式为04-03 92 292 select * from employees where hiredate = str_to_date('04-03 1992','%m-%d %Y'); 293 */ 294 #时间格式的转换为特定格式的字符串 295 SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日') 日期; 296 #查询有奖金的员工的员工名和入职日期,要求该日期格式输出为xx月/xx日 xxxx年 297 SELECT 298 last_name 姓名, 299 DATE_FORMAT (hiredate, '%m月/%d日 %Y年') 入职日期 300 FROM 301 employees 302 WHERE commission_pct IS NOT NULL; 303 304 #求日期之差 305 SELECT DATEDIFF(CURDATE(),'1994-01-21'); 306 307 308 #四、 其他函数################################### 309 SELECT VERSION(); 310 SELECT DATABASE(); 311 SELECT USER(); 312 SELECT PASSWORD('yb'); #加密 313 SELECT MD5('yb'); #加密 314 #五、流程控制函数################################### 315 #if 316 SELECT IF(10>5,1,0); #和excel的if一样 317 SELECT IF(salary<20000,IF(salary<10000,'small','media'),'high') 318 grade #nesting 嵌套 319 FROM employees; 320 321 SELECT last_name, commission_pct, 322 IF(commission_pct IS NULL,'呵呵','哈哈') 备注 323 FROM employees; 324 325 #case多条件判断,可以和select搭配,也可单独使用 326 /* 327 case 常量 328 when 值1 then 显示的值1 329 when 值2 then 显示的值2 330 。。。 331 else 要显示的值n 332 end 333 */ 334 #在部门30的,工资×1.1 335 #在部门40的,工资×1.2 336 #在部门50的,工资×1.3 337 #其他部门,原工资 338 SELECT `department_id`, salary, 339 CASE `department_id` 340 WHEN 30 THEN salary*1.1 341 WHEN 40 THEN salary*1.2 342 WHEN 50 THEN salary*1.3 343 ELSE salary 344 END 345 AS 新工资 346 FROM employees; 347 #excel嵌套大法 348 SELECT department_id,salary, 349 IF(department_id=30,salary*1.1, 350 IF(department_id=40,salary*1.2, 351 IF(department_id=50,salary*1.3,salary)))AS 新工资 352 FROM employees; 353 354 /* 多重if 355 case 356 when 条件1 then 显示的值1 357 when 条件2 then 显示的值2 358 。。。 359 else 要显示的值n 360 end 361 */ 362 #工资<10000,small;10000<=工资<20000,media;20000<工资,high 363 SELECT salary, 364 CASE 365 WHEN salary>20000 THEN 'high' 366 WHEN salary>10000 THEN 'media' 367 ELSE 'small' 368 END 369 AS grade 370 FROM employees; 371 #excel嵌套大法 372 SELECT salary,IF(salary<20000,IF(salary<10000,'small','media'),'high') 373 grade #nesting 嵌套 374 FROM employees; 375 376 ##二、统计函数 377 378 #sum avg max min count 379 #sum avg只能处理数字型,max 、min、count可以字符型 380 #全部忽略null值 381 #可以搭配distinct,去重 382 #和统计函数一同使用的时group by 后的字段。☆☆☆☆☆ 383 384 SELECT SUM(salary),AVG(salary),MAX(salary),MIN(salary),COUNT(salary) 385 FROM employees; 386 387 SELECT SUM(salary),ROUND(AVG(salary),2),MAX(salary),MIN(salary),COUNT(salary) 388 FROM employees; 389 390 SELECT SUM(`commission_pct`),MAX(hiredate) 391 FROM employees; 392 393 SELECT SUM(DISTINCT salary), COUNT(DISTINCT `commission_pct`), 394 SUM(salary),COUNT(`commission_pct`) 395 FROM `employees`; 396 397 #count单独使用 398 SELECT COUNT(*) FROM `employees`;#☆☆☆ 399 SELECT COUNT(1) FROM `employees`; 400 401 #进阶5 分组查询 ------------------------------------------------ 402 /* 403 select 统计函数,字段 404 from 表名 405 【where 包含表名字段的条件】 #不可使用别名 406 group by 字段 #可使用别名 407 【having 包含统计函数的字段】 #可使用别名 408 【order by 字段】 #可使用别名 409 410 */ 411 #简单分组查询:每个部门平均工资 412 SELECT AVG(salary),`department_id` 413 FROM employees 414 GROUP BY `department_id`; 415 #前筛选--分组查询:邮箱中包含a字符的,每个部门平均工资, 416 #where要跟在from 后面一行 417 SELECT AVG(salary),department_id,email 418 FROM employees 419 WHERE email LIKE '%a%' 420 GROUP BY department_id; 421 #有奖金的每个领导手下的员工最高工资 422 SELECT MAX(salary),manager_id 423 FROM employees 424 WHERE commission_pct IS NOT NULL 425 GROUP BY manager_id; 426 #后筛选--分组查询:领导编号>102的每个领导手下员工的最低工资>5000的领导编号 427 #,以及其最低工资 428 SELECT MIN(salary),manager_id 429 FROM employees 430 WHERE manager_id>102 #优先考虑前筛选☆☆☆☆☆ 431 GROUP BY manager_id 432 HAVING MIN(salary)>5000; 433 #按函数--分组查询:按员工姓名长度分组,查询每组个数,筛选员工个数>5的有哪些 434 SELECT COUNT(*),LENGTH(last_name) 435 FROM employees 436 GROUP BY LENGTH(last_name) 437 HAVING COUNT(*)>5; 438 #多字段--分组查询 439 #每个部门每个工种的平均员工工资 440 SELECT AVG(salary),department_id,job_id 441 FROM employees 442 GROUP BY department_id,job_id; 443 #排序--分组查询 444 #每个部门每个工种的员工平均工资,按照平均工资大小降序 445 SELECT AVG(salary),department_id,job_id 446 FROM employees 447 GROUP BY department_id,job_id 448 ORDER BY AVG(salary) DESC; 449 450 #进阶6 多表连接查询----------------------------------------------- 451 #当查询的字段来自多个表 452 #分类:内连接:等值连接、非等值连接、自连接 453 # 外连接:左外连接、右外连接、全外连接 454 # 交叉连接 455 456 ##92版 内连接 457 USE girls; 458 SELECT NAME,boyName FROM beauty ,boys 459 WHERE beauty.`boyfriend_id`=boys.`id`; 460 461 #查询员工名和对应的部门名 462 SELECT last_name,department_name 463 FROM employees , departments 464 WHERE employees.`department_id`=departments.`department_id`; 465 #为表名起别名,且from先执行,所以select 里面的job.id有歧义,只能用别名去标明 466 #查询员工名、工种号、工种名 # 467 #SELECT last_name,employees.job_id,job_title 468 SELECT last_name,e.job_id,job_title 469 FROM employees e, jobs j 470 WHERE e.`job_id`=j.`job_id`; 471 472 473 #筛选--内连接 474 #有奖金的员工名、部门名 475 SELECT last_name,department_name 476 FROM employees e,departments d 477 WHERE e.`department_id`=d.`department_id` 478 AND e.`commission_pct` IS NOT NULL; 479 #查询城市名中第二个字符为o的部门名和城市名 480 EXPLAIN SELECT department_name,city 481 FROM departments d,locations l 482 WHERE d.`location_id`=l.`location_id` 483 AND l.`city` LIKE '_o%'; 484 485 #分组-内连接 486 #查询每个城市的部门个数 487 SELECT COUNT(*), city 488 FROM departments d,locations l 489 WHERE d.`location_id`=l.`location_id` 490 GROUP BY l.`city`; 491 #查询有奖金的每个部门的部门名和部门领导编号,以及该部门最低工资 492 SELECT department_name,e.manager_id,MIN(salary) 493 FROM departments d,employees e 494 WHERE d.`department_id`=e.`department_id` 495 AND e.`commission_pct` IS NOT NULL; 496 497 #三表连接 498 #查询员工名、部门名、所在城市 499 SELECT last_name,department_name,city 500 FROM employees e,departments d,locations l 501 WHERE e.`department_id`=d.`department_id` 502 AND d.`location_id`=l.`location_id`; 503 504 #非等值连接 505 #查询员工工资和工资级别 506 SELECT salary, grade_level 507 FROM employees e,job_grades g 508 WHERE e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`; 509 510 #自连接 511 #查询员工名和上级名称 512 SELECT a.last_name,b.last_name 513 FROM employees a,employees b 514 WHERE a.`manager_id`=b.`employee_id`; 515 516 #99版内连接 517 #查询员工名和对应的部门名 518 SELECT last_name,department_name 519 FROM employees e 520 JOIN departments d 521 ON e.`department_id`=d.`department_id`; 522 523 #为表名起别名,且from先执行,所以select 里面的job.id有歧义,只能用别名去标明 524 #查询员工名、工种号、工种名 # 525 SELECT last_name,e.job_id,job_title 526 FROM employees e 527 JOIN jobs j 528 ON e.`job_id`=j.`job_id`; 529 530 #筛选--内连接 531 #有奖金的员工名、部门名 532 SELECT last_name,department_name 533 FROM employees e 534 JOIN departments d 535 ON e.`department_id`=d.`department_id` 536 WHERE e.`commission_pct` IS NOT NULL; 537 538 539 #查询城市名中第二个字符为o的部门名和城市名 540 SELECT department_name,city 541 FROM departments d 542 JOIN locations l 543 ON d.`location_id`=l.`location_id` 544 WHERE l.`city` LIKE '%o%'; 545 546 #分组-内连接 547 #查询每个城市的部门个数 548 SELECT COUNT(*),city 549 FROM departments d 550 JOIN locations l 551 ON d.`location_id`=l.`location_id` 552 GROUP BY l.`city`; 553 554 #查询有奖金的每个部门的部门名和部门领导编号,以及该部门最低工资 555 SELECT department_name,d.manager_id,MIN(salary) 556 FROM employees e 557 JOIN departments d 558 ON e.`department_id`=d.`department_id` 559 GROUP BY d.`department_name`; 560 561 562 563 #三表连接 564 #查询员工名、部门名、所在城市 565 SELECT last_name,department_name,city 566 FROM departments d 567 JOIN employees e ON e.`department_id`=d.`department_id` 568 JOIN locations l ON d.`location_id`=l.`location_id`; 569 570 #非等值连接 571 #查询员工工资和工资级别 572 SELECT salary, grade_level 573 FROM employees e 574 JOIN job_grades j 575 ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`; 576 577 #自连接 578 #查询员工名和上级名称 579 SELECT a.last_name,b.last_name 580 FROM employees a 581 JOIN employees b ON a.`manager_id`=b.`employee_id`; 582 583 SELECT department_name,COUNT(*) 员工个数 584 FROM departments d INNER 585 JOIN employees e 586 ON d.`department_id`=e.`department_id` 587 GROUP BY d.`department_name` 588 HAVING COUNT(*)>3 589 ORDER BY 员工个数 DESC; 590 591 #左外连接#查询非交集(内连接查询的即为交集) 592 SELECT b.*, bo.boyName 593 FROM beauty b #主表 594 LEFT JOIN boys bo 595 ON b.`boyfriend_id`=bo.`id` 596 WHERE bo.`boyName` IS NULL; 597 #右外连接 598 SELECT bo.boyName,b.* 599 FROM boys bo 600 RIGHT JOIN beauty b 601 ON bo.`id`=b.`boyfriend_id` 602 WHERE bo.`boyName` IS NULL; 603 #----- 604 SELECT bo.*,b.name 605 FROM boys bo 606 LEFT JOIN beauty b 607 ON bo.`id`=b.`boyfriend_id`; 608 609 #交叉连接(笛卡尔乘积) 610 SELECT * FROM beauty; 611 SELECT * FROM boys; 612 SELECT b.*,bo.* 613 FROM beauty b 614 CROSS JOIN boys bo; 615 SELECT b.*,bo.* 616 FROM beauty b,boys bo; 617 ####7种join大法 618 #左拼 619 SELECT * FROM a LEFT JOIN b ON a.id=b.id; 620 #左拼左独有 621 SELECT * FROM a LEFT JOIN b ON a.id=b.id WHERE b.id IS NULL; 622 623 #右拼 624 SELECT * FROM a RIGHT JOIN b ON a.id=b.id; 625 #右拼右独有 626 SELECT * FROM a RIGHT JOIN b ON a.id=b.id WHERE b.id IS NULL; 627 628 #内连接 629 SELECT * FROM a INNER JOIN b ON a.id=b.id ; 630 631 ##全外连接(mysql不支持全外,使用union连接去重的特性,实现full join) 632 SELECT * FROM a LEFT JOIN b ON a.id=b.id 633 UNION 634 SELECT * FROM a RIGHT JOIN b ON a.id=b.id; 635 636 ##左独有 拼 右独有 637 SELECT * FROM a LEFT JOIN b ON a.id=b.id WHERE b.id IS NULL; 638 UNION 639 SELECT * FROM a RIGHT JOIN b ON a.id=b.id WHERE b.id IS NULL; 640 641 642 #习题 那个城市没有部门 643 SELECT l.city ,d.department_name 644 FROM locations l 645 LEFT JOIN departments d 646 ON l.`location_id`=d.`location_id` 647 WHERE d.`department_name` IS NULL; 648 649 #习题 查询部门名为SAL/IT的员工信息 650 SELECT d.department_name,e.* 651 FROM departments d 652 LEFT JOIN employees e #注意主表不同,结果不同(把lfet换成right,39行) 653 ON e.`department_id`=d.`department_id` 654 WHERE d.`department_name` IN( 'SAL' ,'IT'); 655 656 ##进阶7 子查询--------------------------------------- 657 #出现在其他语句的select查询语句为子查询 658 #子查询出现的位置: select后面 659 # 仅支持标量子查询 660 # from后面 661 # 仅支持表子查询(多行多列) 662 # where后面(**)/having后面(**) 663 # 标量子查询(一行一列)√ 664 # 列子查询(多行一列) √ 665 # 行子查询(一行多列) 666 # exists后面 667 # 表子查询 668 /* 669 #where和having后面:标量、列、行子查询 670 特点: 子查询放在小括号内 671 一般放在条件的右侧 672 标量子查询一般搭配单行操作符使用:> < >= <= = <> 673 列子查询一般搭配多行操作符使用 in any/some all 674 查询过程中,子查询优先执行 675 */ 676 ##标量子查询 677 #案例1 谁的工资比Abel高? 678 SELECT * 679 FROM employees 680 WHERE salary>( SELECT salary FROM employees WHERE last_name='Abel'); 681 #案例2 返回job_id和141号员工相同,salary比143号员工高的员工信息 682 SELECT * 683 FROM employees 684 WHERE job_id = 685 (SELECT job_id FROM employees WHERE employee_id=141) 686 AND salary> 687 (SELECT salary FROM employees WHERE employee_id = 143); 688 #案例3 返回工资最少的员工的信息 689 SELECT * 690 FROM employees 691 WHERE salary = (SELECT MIN(salary) FROM employees ); 692 #案例4 查询最低工资大于50号部门的最低工资的部门name和其最低工资(外加多表查询) 693 SELECT MIN (salary), d.department_name 694 FROM employees e 695 JOIN departments d 696 ON e.`department_id` = d.`department_id` 697 GROUP BY d.department_name 698 HAVING MIN (salary) > 699 (SELECT 700 MIN (salary) 701 FROM 702 employees 703 WHERE department_id = 50); 704 ##列子查询 705 #案例1 返回location_id是1400或者1700的部门中所有员工姓名 706 SELECT * 707 FROM employees 708 WHERE department_id IN ( 709 SELECT DISTINCT department_id 710 FROM departments 711 WHERE location_id IN(1400,1700) 712 ); 713 SELECT * 714 FROM employees 715 WHERE department_id =ANY ( 716 SELECT DISTINCT department_id 717 FROM departments 718 WHERE location_id IN(1400,1700) 719 ); 720 # is not in == <>all 721 # is in == =any 722 #返回其他工种中比job_id为'IT-PROG'工种任一工资低的员工号、姓名、jobid、salary 723 SELECT employee_id,last_name,job_id,salary 724 FROM employees 725 WHERE salary < ANY( 726 SELECT DISTINCT salary FROM employees WHERE job_id='IT_PROG' 727 ) AND job_id <> 'IT_PROG'; 728 SELECT employee_id,last_name,job_id,salary 729 FROM employees 730 WHERE salary < ( 731 SELECT DISTINCT MAX(salary) FROM employees WHERE job_id='IT_PROG' 732 ) AND job_id <> 'IT_PROG'; 733 #返回其他工种中比job_id为'IT-PROG'工种*所有*工资低的员工号、姓名、jobid、salary 734 SELECT employee_id,last_name,job_id,salary 735 FROM employees 736 WHERE salary < ALL( 737 SELECT DISTINCT salary FROM employees WHERE job_id='IT_PROG' 738 ) AND job_id <> 'IT_PROG'; 739 SELECT employee_id,last_name,job_id,salary 740 FROM employees 741 WHERE salary < ( 742 SELECT DISTINCT MIN(salary) FROM employees WHERE job_id='IT_PROG' 743 ) AND job_id <> 'IT_PROG'; 744 ##3、行子查询 745 #查询员工编号最小,工资最高的员工信息 746 747 SELECT * FROM employees 748 WHERE employee_id = (SELECT MIN(employee_id) FROM employees) 749 AND salary = (SELECT MAX(salary) FROM employees); 750 751 SELECT * FROM employees e 752 WHERE (e.`employee_id` , e.`salary`) =( 753 SELECT MIN(employee_id) ,MAX(salary) FROM employees); 754 755 756 #二、select后面子查询,**仅支持标量子查询 757 #每个部门的员工个数 758 SELECT d.*,( 759 SELECT COUNT(*) 760 FROM employees e 761 WHERE e.department_id = d.`department_id`) N 762 FROM departments d; 763 SELECT d.* ,COUNT(*) N 764 FROM employees e,departments d 765 WHERE e.`department_id`=d.`department_id` 766 GROUP BY e.`department_id`; 767 #员工号102的部门名 768 SELECT (SELECT d.department_name 769 FROM employees e,departments d 770 WHERE e.department_id=d.department_id 771 AND e.employee_id=102) N 772 ; 773 ##from 后面跟表子查询,表子查询必须要起别名 774 #案例:每个部门的平均工资的工资等级 775 SELECT a.avge,a.department_id, j.`grade_level` 776 FROM ( 777 SELECT AVG(salary) avge,department_id 778 FROM employees 779 GROUP BY department_id 780 ) a 781 , job_grades j 782 WHERE a.avge BETWEEN j.`lowest_sal` AND j.`highest_sal`; 783 SELECT a.*, j.`grade_level` 784 FROM ( 785 SELECT AVG(salary) avge,department_id 786 FROM employees 787 GROUP BY department_id 788 ) a 789 JOIN job_grades j 790 ON a.avge BETWEEN j.`lowest_sal` AND j.`highest_sal`; 791 792 ##exists (相关子查询) 793 SELECT EXISTS( 794 SELECT salary FROM employees WHERE salary = 23000 795 ); 796 #返回布尔向量,0或1 797 #有员工的部门名 798 SELECT d.department_name 799 FROM departments d 800 WHERE d.department_id IN (SELECT e.department_id FROM employees e); 801 802 SELECT d.department_name 803 FROM departments d 804 WHERE EXISTS 805 (SELECT * FROM employees e WHERE e.`department_id`=d.`department_id`); 806 807 (SELECT 808 e.* 809 FROM 810 employees e ,departments d 811 WHERE e.`department_id` = d.`department_id`); 812 #案例2 没有女朋友的男神信息 813 USE girls; 814 SELECT bo.* 815 FROM boys bo 816 WHERE NOT EXISTS ( 817 SELECT * FROM beauty b WHERE b.`boyfriend_id`=bo.`id` 818 ); 819 ##习题:查询各部门中工资比本部门平均工资高的员工信息 820 SELECT e.* 821 FROM employees e,( 822 SELECT AVG(salary) av,department_id 823 FROM employees 824 GROUP BY department_id 825 )a 826 WHERE e.`department_id`=a.department_id 827 AND e.`salary`>a.av; 828 829 830 SELECT e.* ,e.`department_id` FROM employees e 831 JOIN ( 832 SELECT AVG(salary) av,department_id 833 FROM employees 834 GROUP BY department_id 835 )a 836 ON e.`department_id`=a.department_id 837 WHERE e.`salary`>a.av; 838 839 ##进阶8 分页查询-------------------------------------------- 840 #伪代码 841 # select 查询列表 842 # from 表名 843 # 【join type 844 # where group by having order by 】 845 # limit 【起始页=0】,size 846 #公式:******limit (page-1)*size,size********* 847 #*******************查询虚拟表的极值order by xx desc limit 1******************* 848 #案例1 查询前5条员工信息 849 SELECT * FROM employees LIMIT 0,5; #从0开始!!!!!!,substr是1开始 850 SELECT * FROM employees LIMIT 5; 851 #案例2 有奖金的员工信息,工资较高的前10名 852 SELECT * 853 FROM employees 854 WHERE commission_pct IS NOT NULL 855 ORDER BY salary DESC 856 LIMIT 0,10; 857 #执行顺序 858 /* 859 select 查询列表 7 860 from 表名 1 861 连接类型 join 表2 2 #产生一个笛卡尔乘积 862 on 连接条件 3 #根据连接条件筛选 863 where 筛选条件 4 864 group by 分组列表 5 865 having 分组后筛选 6 866 order by 排序列表 8 867 limit 偏移,条目数 9 868 */ 869 870 #子查询经典习题 871 #案例1 查询平均工资最低的部门信息 872 SELECT d.* 873 FROM departments d 874 JOIN ( 875 SELECT AVG(salary) ag ,e.department_id 876 FROM employees e 877 GROUP BY e.`department_id` 878 ORDER BY a.ag 879 LIMIT 0,1 880 ) a 881 ON d.`department_id`=a.department_id 882 ; 883 #平均工资最高的job信息 884 SELECT j.* 885 FROM jobs j,( 886 SELECT AVG(salary) av,job_id 887 FROM employees 888 GROUP BY job_id 889 ORDER BY av DESC 890 LIMIT 1 891 ) a 892 WHERE j.`job_id`=a.job_id; 893 894 #查询平均工资高于公司平均工资的部门 895 SELECT a.department_id,a.av 896 FROM ( 897 SELECT AVG(salary) av,department_id 898 FROM employees 899 GROUP BY department_id 900 ) a 901 WHERE a.av>( 902 SELECT AVG(salary) FROM employees 903 ); 904 #查询公司中所有manager的详细信息 905 SELECT b.* 906 FROM employees a 907 JOIN employees b 908 ON a.`manager_id`=b.`employee_id` 909 GROUP BY b.`employee_id`; 910 911 SELECT * 912 FROM employees 913 WHERE employee_id = ANY( 914 SELECT DISTINCT manager_id 915 FROM employees 916 GROUP BY manager_id 917 ); 918 #各部门中,最高工资最低的那个部门 的最低工资为 919 SELECT MIN(salary) 920 FROM employees 921 WHERE department_id =( 922 SELECT department_id 923 FROM employees a 924 GROUP BY department_id 925 ORDER BY MAX(salary) 926 LIMIT 1) 927 ; 928 #查询平均工资最高的部门的manager信息 929 #where 标量子查询结果为null时,如何判断 930 SELECT * 931 FROM employees e 932 RIGHT JOIN ( 933 SELECT manager_id 934 FROM employees 935 GROUP BY department_id 936 ORDER BY AVG(salary) DESC 937 LIMIT 1 938 ) a 939 ON IFNULL(e.manager_id,1) = IFNULL(a.manager_id,1) ; 940 941 SELECT 942 * 943 FROM 944 employees e 945 WHERE IFNULL (e.manager_id, 1) = IFNULL ( 946 (SELECT 947 manager_id 948 FROM 949 employees 950 GROUP BY department_id 951 ORDER BY AVG (salary) DESC 952 LIMIT 1),1 953 ); 954 955 #查询生日在1988-1-1后的学生姓名和专业名称 956 USE student; 957 SELECT s.`studentname`,m.`majorname` 958 FROM student s 959 JOIN major m 960 ON s.`majorid`=m.`majorid` 961 WHERE DATEDIFF(s.`borndate`,'1988-1-1')>0; 962 #每个专业的男生女生人数 963 SELECT m.`majorname`, sex,COUNT(*) 964 FROM student s,major m 965 WHERE s.`majorid`=m.`majorid` 966 GROUP BY s.majorid , sex; 967 #变横行 968 SELECT majorid , 969 (SELECT COUNT(*) FROM student WHERE sex="男" AND majorid=s.`majorid`) 男, 970 (SELECT COUNT(*) FROM student WHERE sex="女" AND majorid=s.`majorid`) 女 971 FROM student s 972 GROUP BY majorid; 973 #查询专业和张翠山一样的学生的最低分 974 SELECT MIN(score) 975 FROM student s 976 JOIN result r 977 ON s.`studentno`=r.`studentno` 978 WHERE majorid=( 979 SELECT majorid 980 FROM student 981 WHERE studentname = '张翠山' 982 ); 983 #查询哪个专业没有学生,分别左连接,右连接 984 SELECT m.* 985 FROM major m 986 LEFT JOIN ( 987 SELECT COUNT(*) AS a, majorid 988 FROM student 989 GROUP BY majorid 990 ) n 991 ON m.`majorid`=n.majorid 992 WHERE n.a IS NULL; 993 994 #没有成绩的学生人数 995 SELECT COUNT(*) 996 FROM result r 997 RIGHT JOIN student s 998 ON r.`studentno`=s.`studentno` 999 WHERE r.`id` IS NULL; 1000 1001 ##进阶9 联合查询----------------------------------------------- 1002 /* 语法:查询语句1 1003 union 【all】 1004 查询语句2 1005 特点: 1006 查询结果来自多个表,且各表之间无关键列索引 1007 1、查询列数一致 1008 2、每个查询语句的列的排列一致 1009 3、union会去重,显示全部为union all 1010 */ 1011 SELECT c.id ,c.name FROM china c 1012 UNION ALL 1013 SELECT s.id ,s.name FROM stuinfo s; 1014 1015 ###DML语言 database manipulate language 1016 # 插入insert 1017 # 修改update 1018 # 删除delete 1019 1020 #插入语句 1021 #方式一:insert into 表名(列名) values(值,'值') 1022 1023 USE girls; 1024 INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id) 1025 VALUES(13,'安妮·海瑟薇','女','1980-1-1','188888888',NULL,NULL); 1026 1027 #变量nullable,用null作为该字段值,或者不写该字段 1028 INSERT INTO beauty(id,NAME,sex,borndate,phone) 1029 VALUES(14,'三上悠亚','女','1988-1-1','288888888'); 1030 1031 #列的顺序可以调换 1032 #字段个数和字段值必须一一对应 1033 #可以省略列名,默认为所有字段,且按照表中顺序排列 1034 INSERT INTO beauty 1035 VALUES(15,'妲露拉·莱莉','女','1982-1-1','388888888',NULL,NULL); 1036 1037 #方式二:insert into 表名 set 字段名=值... 1038 INSERT INTO beauty 1039 SET id=16,NAME='刘涛',phone='12345678'; 1040 1041 #两种方式 PK 1042 1043 #方式一可以插入多行 1044 INSERT INTO beauty(id,NAME,sex,borndate,phone) 1045 VALUES(17,'高圆圆','女','1988-10-10','488888888'), 1046 (18,'白百何','女','1989-01-10','588888888'); 1047 1048 INSERT INTO beauty #效率高********** 1049 SELECT 17,'高圆圆','女','1988-10-10','488888888' UNION#***** 1050 SELECT 18,'白百何','女','1989-01-10','588888888'; 1051 1052 #方式一支持子查询#行子查询的结果为beauty的新值 1053 INSERT INTO beauty(id,NAME,phone) 1054 SELECT 19,'唐艺昕','688888888'; 1055 1056 #修改单表记录 1057 #语法 update 表名 set 字段名=值.... where 筛选条件 1058 UPDATE beauty 1059 SET NAME='唐嫣' 1060 WHERE id=15; 1061 1062 #修改多表记录 1063 #修改张无忌的女朋友电话为18866669999 1064 UPDATE beauty b JOIN boys bo 1065 ON b.`boyfriend_id`=bo.`id` 1066 SET phone = '18866669999' 1067 WHERE bo.`boyName`='张无忌'; 1068 #没有男朋友的女神的男朋友都为id=2 1069 UPDATE beauty b LEFT JOIN boys bo 1070 ON b.`boyfriend_id`=bo.`id` 1071 SET b.`boyfriend_id`=2 1072 WHERE bo.`id` IS NULL; 1073 1074 #删除语句 1075 #方式一 1076 #单表删除 ,LIMIT 2 b表示删除两条记录 1077 DELETE FROM beauty WHERE id=19 LIMIT 2; 1078 1079 #多表删除 1080 #删除黄晓明的信息以及他女朋友的信息 1081 DELETE bo,b 1082 FROM boys bo JOIN beauty b 1083 ON b.`boyfriend_id`=bo.`id` 1084 WHERE bo.`boyName`='黄晓明'; 1085 1086 #方式二 1087 TRUNCATE TABLE boys; 1088 1089 #两种方式PK 筛 率 断 返 滚 1090 /* 1091 1.delete可以加where,truncate不能 1092 2.truncate效率高 1093 3.对于自增列,delete删除后在插入,从断点处记录, 1094 truncate删除后从1 开始记录 1095 4.truncate无返回值,delete显示删除了多少行(多少行受影响) 1096 5.truncate删除不能回滚,delete删除可以回滚 1097 */ 1098 SELECT * FROM boys; 1099 1100 DELETE FROM boys; 1101 TRUNCATE TABLE boys; 1102 INSERT INTO boys(boyName,userCP) 1103 VALUES('张无忌',100), 1104 ('鹿晗',800), 1105 ('段誉',300); 1106 1107 1108 ###DDL数据定义语言 1109 #库的管理,表的管理 1110 #库、表的创建create、修改alter,管理drop 1111 #位置 programdata/mysql/data 1112 1113 ##库的管理 1114 #库的创建 1115 CREATE DATABASE IF NOT EXISTS books; 1116 #库的修改 1117 RENAME DATABASE books TO newbooks;#不稳定 1118 #修改字符集 1119 ALTER DATABASE books CHARACTER SET gbk; 1120 #库的删除 1121 DROP DATABASE IF EXISTS books; 1122 1123 ##表的管理 1124 #表的创建 1125 #create table 表名( 1126 # 列名 类型 【长度,约束】, 1127 # 列名 类型 【长度,约束】 1128 # ); 1129 CREATE DATABASE IF NOT EXISTS books; 1130 1131 CREATE TABLE IF NOT EXISTS book ( 1132 id INT, 1133 bookname VARCHAR(20), #(20)为必须 1134 booauthorid INT, 1135 publishtime DATETIME 1136 ); 1137 CREATE TABLE author( 1138 id INT, 1139 b_name VARCHAR(20), 1140 nation VARCHAR(20) 1141 ) 1142 DESC author; 1143 DESCRIBE author; 1144 1145 #表的修改 1146 DESCRIBE book; 1147 #修改列名 1148 ALTER TABLE book CHANGE COLUMN publishtime pubdate DATETIME; 1149 #修改类型或约束 1150 ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP; 1151 #添加新列 1152 ALTER TABLE book ADD COLUMN annual DOUBLE ; 1153 ALTER TABLE stuinfo ADD COLUMN sex CHAR AFTER id; 1154 ALTER TABLE stuinfo ADD COLUMN fam_id INT FIRST; 1155 #删除列 1156 ALTER TABLE book DROP COLUMN annual; 1157 #修改表名 1158 ALTER TABLE author RENAME bookauthor; 1159 1160 ##表的删除 1161 DROP TABLE IF EXISTS bookauthor; 1162 SHOW TABLES; 1163 1164 ##表的复制 1165 CREATE TABLE author( 1166 id INT, 1167 b_name VARCHAR(20), 1168 nation VARCHAR(20) 1169 ); 1170 INSERT INTO author 1171 VALUES 1172 (1,'村上春树','日本'), 1173 (2,'路遥','中国'), 1174 (3,'王小波','中国'); 1175 1176 #仅复制表的结构,跨库:库名.表名 1177 CREATE TABLE copy LIKE author; 1178 #复制表的内容+结构 1179 CREATE TABLE copy1 1180 SELECT * FROM author; 1181 #只复制部分数据 1182 CREATE TABLE copy2 1183 SELECT id ,nation 1184 FROM author WHERE nation='中国'; 1185 #仅复制某些字段的结构 1186 CREATE TABLE copy3 1187 SELECT id ,nation 1188 FROM author 1189 WHERE 0; #where 1=2; 1190 1191 ###常见数值类型 1192 /* 1193 数值型:整数、小数(定点数、浮点数) 1194 字符型:较短文本char、varchar, 1195 较长文本text、blob(较长二进制) 1196 日期型: 1197 */ 1198 ##数值型: 1199 /*整数:tinyint(3)、smallint(5)、mediumint(7)、int(10)、bigint 1200 int有符号为正负最大10位,27********,无符号为最大正10位,49******** 1201 特点: 1。默认为有符号(-),unsgined关键字表示无符号 1202 2。数字超过界值,警告,且用界值填充 1203 3。有默认长度,长度表示显示的最大宽度,位数不够用0填补,但必须搭配zerofill 1204 4。zerofill只能为无符号 1205 */ 1206 USE test; 1207 DROP TABLE tab_int; 1208 CREATE TABLE tab_int( 1209 integer1 INT, 1210 integer2 INT UNSIGNED, 1211 integer3 INT(10) ZEROFILL 1212 ); 1213 1214 INSERT INTO tab_int VALUES (-1234567890,1234567890,123); 1215 INSERT INTO tab_int VALUES (-1234567890,12345678901,123); 1216 DESC tab_int; 1217 SELECT * FROM tab_int; 1218 /*小数: 1219 浮点型float(M,D)、double(M,D) 1220 定点型dec(M,D)/decimal(M,D) 1221 通用的情况下,优先float>double>decimal 1222 特点: 1。M表示整数+小数位数 1223 2.D表示小数位数 1224 3.如果数值位数超过范围,则插入临界值 1225 4.M D都可以省略,float和double随数据长度变化,但默认decimal(10,0) 1226 5.decimal精度高,用于如货币运算 1227 */ 1228 CREATE TABLE tab_dem( 1229 d1 FLOAT(5,2), 1230 d2 DOUBLE(5,3), 1231 d3 DECIMAL 1232 ); 1233 DROP TABLE tab_dem; 1234 INSERT INTO tab_dem(d1) VALUES(123.12); 1235 INSERT INTO tab_dem(d2) VALUES(123.1); 1236 1237 SELECT * FROM tab_dem; 1238 DESC tab_dem; 1239 1240 ##文本类型 1241 #较短文本 char varchar (二进制binary varbinary) 1242 #较长文本 text blob(二进制) 1243 1244 #特点 1245 /* 1246 写法 M 特点 1247 char char(M) 最大字符数,可以省略,默认1 固定长度 1248 varchar varchar(M) 最大字符数,不接省略 可变长度 1249 1250 空间的耗费 效率 1251 比较耗费 较高 1252 比较节省 较低 1253 1254 1255 */ 1256 #枚举 enum 1257 CREATE TABLE tab_enum( 1258 e1 ENUM('a','b','c') 1259 ); 1260 DESC tab_enum; 1261 INSERT INTO tab_enum VALUES 1262 ('a'), #不区分大小写 1263 ('c'); #不在列举范围,则插入值为空 1264 SELECT * FROM tab_enum; 1265 1266 #集合 set 1267 CREATE TABLE tab_set( 1268 s1 SET('a','b','c') 1269 ); 1270 INSERT INTO tab_set VALUES 1271 ('a'), #不区分大小写 1272 ('a,c'); #可加两个 1273 SELECT * FROM tab_set; 1274 1275 ##日期类型 1276 /*分类: 1277 date日期 1278 time时间 1279 year年 1280 字节 范围 时区 1281 datetime 8 1000-9999 不受时区影响 1282 timestamp 4 1970-2038 受影响 1283 1284 */ 1285 #datetime和timestamp(受时区,语法模式、版本影响,但更能反映当前时区的真实时间) 1286 CREATE TABLE tab_date( 1287 d1 DATETIME, 1288 d2 TIMESTAMP 1289 ); 1290 INSERT INTO tab_date 1291 VALUES (NOW(),NOW()); 1292 SELECT * FROM tab_date; 1293 #system时间为+8:00东八区 1294 SHOW VARIABLES LIKE 'time_zone'; 1295 1296 SET time_zone = '+9:00'; 1297 SELECT DATE(NOW()); 1298 ##常见约束 1299 /* 1300 分类:六大约束 1301 1,not null 保证该字段不为空 1302 如ID、姓名 1303 2,default默认 保证该字段有默认值 1304 如 1305 3,primary key主键 用于保证该字段有唯一性,且非空 1306 比如学号、编号 1307 4,unique唯一键 用于保证该字段具有唯一性,可以为空 1308 比如座位号 1309 5,check【mysql不支持】 1310 比如0<年龄<99 1311 6,foreign key外键 用于限制两表关联列在主表中该列的值 1312 比如:employees.department_id in departments.department_id 1313 1314 在创建表和修改表时,添加约束 1315 1316 分类: 列级约束 :(除外键)六大常见约束都支持,但是check无效果、foreign key无效果 1317 表级约束 :(三键)除了非空、默认都支持 1318 1319 主键和唯一键的PK 1320 唯一性 是否允许为空 一个表有几个 是否允许组合 1321 主键 √ × 最多一个 √,但是不推荐 1322 唯一键 √ √(只能有一个空) 可以有多个 √,但是不推荐 1323 1324 组合的意思是,让ID和name的组合如:ID_name唯一且不为空 1325 1326 外键:1,要求在从表(stinf)设置外键 1327 2,从表(stinf)的外键列要求和主表(major)的类型一致或兼容 1328 3,主表(major)的关联列必须是一个key (一般为主键) 1329 4,插入数据时,先插主表(major),后从表(stinf) 1330 5,删除数据时,先删从表(stinf),后主表(major)***级联删除和级联置空 1331 1332 */ 1333 1334 #列级约束 1335 1336 CREATE DATABASE constrain; 1337 CREATE TABLE stinf( 1338 id INT PRIMARY KEY, #主键 1339 stuname VARCHAR(20) NOT NULL UNIQUE,#非空 & 唯一键 1340 gender CHAR(1) CHECK(gender='男' OR gender='女'),#核查 1341 seat INT UNIQUE,#唯一键 1342 age INT DEFAULT 18,#默认 1343 majorid INT REFERENCES major(id)#外键 1344 ); 1345 1346 CREATE TABLE major( 1347 id INT PRIMARY KEY, 1348 mname VARCHAR(20) 1349 ); 1350 DESC stinf; 1351 SHOW INDEX FROM stinf; #查看主键、外键、唯一键 1352 1353 #表级约束 1354 DROP TABLE IF EXISTS stinf; 1355 CREATE TABLE IF NOT EXISTS stinf( 1356 id INT, 1357 stuname VARCHAR(20), 1358 gender CHAR(1), 1359 seat INT, 1360 age INT, 1361 majorid INT, 1362 CONSTRAINT pk PRIMARY KEY(id),#主键 1363 CONSTRAINT uq UNIQUE(seat),#唯一键 1364 CONSTRAINT ck CHECK(gender IN ('男','女')),#核查 1365 CONSTRAINT fk_stinf_major FOREIGN KEY(majorID) 1366 REFERENCES major(id)#外键 1367 #constriant用来给键起名字 1368 ); 1369 SHOW INDEX FROM stinf; #查看主键、外键、唯一键 1370 DROP TABLE IF EXISTS stinf; 1371 1372 CREATE TABLE IF NOT EXISTS stinf( 1373 id INT, 1374 stuname VARCHAR(20), 1375 gender CHAR(1), 1376 seat INT, 1377 age INT, 1378 majorid INT, 1379 PRIMARY KEY(id),#主键 1380 UNIQUE(seat),#唯一键 1381 CHECK(gender IN ('男','女')),#核查 1382 FOREIGN KEY(majorID) REFERENCES major(id)#外键 1383 1384 ); 1385 SHOW INDEX FROM stinf; #查看主键、外键、唯一键 1386 #通用 1387 DROP TABLE IF EXISTS stinf; 1388 1389 CREATE TABLE IF NOT EXISTS stinf( 1390 id INT PRIMARY KEY, #主键 1391 stuname VARCHAR(20) NOT NULL,#非空 1392 gender CHAR(1) CHECK(gender='男' OR gender='女'),#核查 1393 seat INT UNIQUE,#唯一键 1394 age INT DEFAULT 18,#默认 1395 majorid INT, 1396 CONSTRAINT fk_stinf_major FOREIGN KEY(majorid) 1397 REFERENCES major(id)#外键 1398 ); 1399 SHOW INDEX FROM stinf; #查看主键、外键、唯一键 1400 1401 ##修改约束 1402 /* 1403 1404 1405 */ 1406 DROP TABLE IF EXISTS stinf; 1407 1408 CREATE TABLE IF NOT EXISTS stinf( 1409 id INT, 1410 stuname VARCHAR(20), 1411 gender CHAR(1) NOT NULL, 1412 seat INT, 1413 age INT, 1414 majorid INT 1415 ); 1416 #列级约束修改 1417 ALTER TABLE stinf MODIFY COLUMN id INT PRIMARY KEY ; 1418 ALTER TABLE stinf MODIFY COLUMN age INT DEFAULT 18; 1419 DESC stinf; 1420 SHOW INDEX FROM stinf; 1421 #表级约束修改 1422 #主键也可以这样去添加,但是不能添加constraint 限制名 1423 ALTER TABLE stinf ADD CONSTRAINT u_seat UNIQUE(seat); 1424 ALTER TABLE stinf 1425 ADD CONSTRAINT fk_major_stinf FOREIGN KEY (majorid) REFERENCES major (id); 1426 DESC stinf; 1427 SHOW INDEX FROM stinf; 1428 1429 ##修改表时删除约束 1430 #1删非空约束 1431 ALTER TABLE stinf MODIFY COLUMN gender CHAR(1); 1432 #2删默认约束 1433 ALTER TABLE stinf MODIFY COLUMN age INT; 1434 #3删主键 1435 ALTER TABLE stinf DROP PRIMARY KEY; 1436 #4删唯一键 1437 ALTER TABLE stinf DROP INDEX seat; 1438 #5删除外键 1439 ALTER TABLE stinf DROP FOREIGN KEY fk_major_stinf; 1440 SHOW INDEX FROM FROM stinf; 1441 1442 ##级联删除:关于从表有外键时,删除数据biubiu先删主表,级联可以先删从表 1443 #级联删除 1444 ALTER TABLE student ADD CONSTRAINT fk_stu_maj 1445 FOREIGN KEY(majorid) REFERENCES major(majorid) ON DELETE CASCADE; 1446 DELETE FROM major WHERE majorid=3; 1447 #级联置空 1448 ALTER TABLE student DROP FOREIGN KEY fk_stu_maj; 1449 ##无法设置成功!!?? 1450 ALTER TABLE student ADD CONSTRAINT fk_stu_maj 1451 FOREIGN KEY(majorid) REFERENCES major(majorid) ON DELETE SET NULL; 1452 DELETE FROM major WHERE majorid=2; 1453 1454 1455 1456 #标识列 1457 /* 1458 1 必须搭配 键(只限mysql) 1459 2 至多一个标识列 1460 3 标识列类型只能是数值 1461 4 步长设置通过SET auto_increment_increment = 2; 1462 5 标识列初始值可通过手动添加 1463 1464 */ 1465 DROP TABLE tab_auto; 1466 CREATE TABLE tab_auto( 1467 id INT PRIMARY KEY AUTO_INCREMENT, 1468 NAME VARCHAR(20) 1469 ); 1470 1471 INSERT INTO tab_auto(id,NAME) VALUES(NULL,'john'); 1472 INSERT INTO tab_auto(NAME) VALUES('john'); 1473 INSERT INTO tab_auto VALUES(NULL,'john'); 1474 INSERT INTO tab_auto VALUES(5,'lily'); #相当于设置了起始值 1475 INSERT INTO tab_auto VALUES(NULL,'john'); 1476 1477 TRUNCATE TABLE tab_auto; 1478 1479 SELECT * FROM tab_auto; 1480 SHOW VARIABLES LIKE '%auto_increment%'; 1481 SET auto_increment_increment = 2; #设置步长 1482 SET auto_increment_offset = 3; #mysql无作用 1483 #修改表时 添加删标识列 1484 DROP TABLE tab_auto; 1485 CREATE TABLE tab_auto( 1486 id INT, 1487 NAME VARCHAR(20) 1488 ); 1489 ALTER TABLE tab_auto MODIFY id INT PRIMARY KEY AUTO_INCREMENT; 1490 ALTER TABLE tab_auto MODIFY id INT; 1491 1492 ##事务 1493 /*分类: 1494 隐式事务:insert update delete 1495 显式事务:set autocommit=0; 1496 strat transaction; 1497 select insert update delete; 1498 ***** 无create alter drop ****** 1499 commit; / rollback; 1500 ACID 1501 1 原子性atomicity:一个事务不可再分割,要么都执行要么都不执行 1502 2 一致性consistency:一个事务执行会使数据从一个状态切换到另一个状态 1503 3 隔离性isolation:一个事务的执行不受其他事务的影响 1504 3 持久性durability:一个事务的提交会永久改变数据库的数据 1505 1506 三种数据问题: 1507 1脏读:T1 T2 ,T2更新没提交,T1读取,读取了临时无效的信息,若T2回滚 1508 2不可重复度:T1读取,T2更新,T1再读取则信息变化 1509 3幻读:T1读取,T2更新某些行,T1再读取,出现多行数据 1510 1511 事务隔离级别: 1512 脏读 不可重复读 幻读 1513 read uncommitted √ √ √ 1514 read committed × √ √ 1515 repeatable read × × √ 1516 serializable × × × 1517 1518 mysql默认repeatable read 1519 Oracle默认read committed 1520 */ 1521 #查看当前隔离级别 1522 SELECT @@tx_isolation; 1523 #设置隔离级别 1524 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 1525 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 1526 1527 SELECT @@tx_isolation; 1528 #事务中delete 和truncate 的区别 1529 1530 SET autocommit=0; 1531 START TRANSACTION; 1532 DELETE FROM stuinfo; 1533 ROLLBACK; 1534 SELECT * FROM stuinfo; 1535 1536 SET autocommit=0; 1537 START TRANSACTION; 1538 TRUNCATE stuinfo; 1539 ROLLBACK; 1540 SELECT * FROM stuinfo; 1541 COMMIT; 1542 1543 #演示savepoint的使用 1544 INSERT INTO stuinfo VALUES(1,1,'s','yb'); 1545 INSERT INTO stuinfo VALUES(2,2,'x','lz'); 1546 SELECT * FROM stuinfo; 1547 COMMIT; 1548 1549 SET autocommit=0; 1550 START TRANSACTION; 1551 DELETE FROM stuinfo WHERE id=1; 1552 SAVEPOINT a; 1553 DELETE FROM stuinfo WHERE id=2; 1554 ROLLBACK TO a; 1555 SELECT * FROM stuinfo; 1556 COMMIT; 1557 ##视图 1558 /* 1559 含义:虚拟表,和普通表一样 1560 mysql5.1出现的新特性,是通过表动态生成的数据 1561 1562 比如:一个班里面 分化出一个舞蹈班,有需要时,舞蹈班就可以直接出现 1563 1564 视图和表的PK: 1565 1 创建语法不通 view table 1566 2 视图只占sql语句的字节,表占空间 1567 3 视图一般不能增删改 1568 1569 1570 */ 1571 1572 #查询各部门平均工资级别 1573 USE myemployees; 1574 CREATE VIEW myv1 1575 AS 1576 SELECT AVG(salary) ag,department_id 1577 FROM employees 1578 GROUP BY department_id; 1579 1580 SELECT v.ag ,j.`grade_level` FROM myv1 v 1581 JOIN job_grades j 1582 ON v.`ag` BETWEEN j.`lowest_sal` AND j.`highest_sal`; 1583 1584 #查询平均工资最低的部门信息 1585 SELECT d.department_name, m.department_id, m.ag 1586 FROM myv1 m JOIN departments d 1587 ON d.`department_id`=m.`department_id`; 1588 1589 #视图的修改 1590 CREATE OR REPLACE VIEW myv1 1591 AS 1592 SELECT AVG(salary) AS average_salary,department_id 1593 FROM employees 1594 GROUP BY department_id; 1595 1596 ALTER VIEW myv1 1597 AS 1598 SELECT AVG(salary) ag,department_id 1599 FROM employees 1600 GROUP BY department_id; 1601 1602 #视图的删除 1603 CREATE VIEW myv2 1604 AS 1605 SELECT department_id 1606 FROM employees 1607 GROUP BY department_id; 1608 1609 DROP VIEW myv1, myv2; 1610 #视图的查看 1611 DESC myv2; 1612 SHOW CREATE VIEW myv2; 1613 SHOW CREATE VIEW myv2\G; #在 DOS中使用 1614 1615 #通过视图增删改原始表 1616 /* 1617 在视图包含以下情况不能insert update delete包含以下sql语句: 1618 1 分组函数、instinct、group by 、having 、union、union all 1619 2 常量视图 1620 3 select包含子查询 1621 4 join 1622 5 from一个不能更新的视图 1623 6 where子句的子查询引用了from子句的表 1624 1625 */ 1626 ##变量 1627 /* 1628 系统变量:全局变量、会话变量 1629 自定义变量:用户变量、局部变量 1630 */ 1631 1632 #一、系统变量、会话变量(一个查询编辑器一个会话) 1633 /* 1634 变量由系统提供,不是用户定义,属于服务器层面 1635 1636 注意:如果是全局变量,则需要加global,如果是会话级别,则需要加session,默认session 1637 1638 使用语法: 1639 1,查看所有变量: 1640 show global|session variables; 1641 1642 2,查看满足条件的部分系统变量 1643 show global|session variable like '%char%'; 1644 1645 3,查看某个指定变量的值 1646 select @@global|session.变量名; 1647 select @@global.flush; 1648 1649 4,为某个变量赋值(跨连接有效,不能跨重启) 1650 set @@global|session 变量名=值; 1651 set global|session 变量名=值; 1652 1653 */ 1654 #自定义变量 1655 /* 1656 声明、赋值、使用(查看、比较、运算) 1657 1658 作用域 定义和使用的位置 语法 1659 用户变量 当前会话 会话的任何地方 必须加@,不限制类型 1660 局部变量 begin end中 只能在begin end中的第一句话 不加@,限定类型 1661 */ 1662 #1,用户变量 : 作用域:当前会话 1663 1664 #1 声明并初始化 1665 SET @用户变量名=值; 1666 SET @用户变量名:=值; 1667 SELECT @用户变量名:=值; 1668 1669 #2 赋值(更新用户变量的值) 1670 #方式一 1671 SET @用户变量名=值; 1672 SET @用户变量名:=值; 1673 SELECT @用户变量名:=值; 1674 1675 #方式二 1676 SELECT 字段 INTO @用户变量名 1677 FROM 表名; 1678 1679 #使用 1680 SELECT @用户变量名; 1681 1682 #案例 1683 SET @count:=1; 1684 SELECT COUNT(*) INTO @count FROM employees; 1685 SELECT @count; 1686 1687 #2,局部变量 1688 /* 1689 作用域:只在定义它的begin 和 end 中有效 1690 1691 */ 1692 1693 #声明 ---------必须放在begin后面第一句---------------------- 1694 DECLARE 变量名 类型; 1695 DECLARE 变量名 类型 【DEFAULT 值】; 1696 1697 #赋值 1698 #方式一 1699 SET 用户变量名=值; 1700 SET 用户变量名:=值; 1701 SELECT @用户变量名:=值; 1702 1703 #方式二 1704 SELECT 字段 INTO 用户变量名 FROM 表名; 1705 1706 #使用 1707 SELECT 局部变量; 1708 1709 ##存储过程和函数 1710 /* 1711 好处:提高代码的重用性、简化操作 1712 */ 1713 1714 #存储过程 1715 /* 1716 定义:一组预先编译好的SQL语句集合 1717 1718 1719 一、创建语法 1720 create procedure 存储过程名(参数列表) 1721 begin 1722 存储过程体(一组合法的SQL语句) 1723 end 1724 1725 注意: 1726 1,参数列表包含三部分: 1727 参数模式 参数名 参数类型 1728 in id int 1729 1730 参数模式: 1731 in :改参数可以作为输入,也就是该参数需要调用方 传入值 1732 out : 该参数可以作为输出,也就是该参数可以作为返回值 1733 inout : 该参数既可以作为输出,又可以作为输入,即既需要传入值,也能返回值 1734 1735 2,如果存储过程体只有一句话, begin 和 end 可以省略 1736 存储过程体每条sql均需要结尾加; 1737 存储过程的结尾可以使用 delimiter 重新设置 1738 *********delimiter在新连接中要去dos重新设置************* 1739 语法: delimiter 结束标记 1740 案例: delimiter $ 1741 1742 二、调用语法 1743 Call 存储过程名(实参列表); 1744 */ 1745 ##空参列表 1746 #案例:给girls.admin添加5条数据 1747 1748 DELIMITER $ 1749 CREATE PROCEDURE myp1() 1750 BEGIN 1751 INSERT INTO admin(username,PASSWORD) 1752 VALUES('yb1',123),('yb2',123),('yb3',123),('yb4',123),('yb5',23); 1753 END $ 1754 1755 CALL myp1()$ 1756 SELECT * FROM admin$ 1757 1758 ##in列表 1759 #案例1:创建存储过程实现:根据女神名查询对应的男生信息 1760 1761 CREATE PROCEDURE myp2(IN beautyname VARCHAR(20)) 1762 BEGIN 1763 SELECT bo.* 1764 FROM boys bo 1765 LEFT JOIN beauty b ON b.boyfriend_id=bo.id 1766 WHERE b.name=beautyname ; 1767 END $ 1768 1769 CALL myp2('热巴')$ 1770 1771 #出现 Incorrect string value: '\xC8\xC8\xB0\xCD' for column,表示字符集不匹配 1772 SET NAMES gbk$ #(sqlyog默认utf8, dos默认gbk) 1773 1774 #案例2:创建存储过程实现,用户是否登录成功 1775 1776 CREATE PROCEDURE myp3(IN username VARCHAR(20),IN PASSWORD VARCHAR(20)) 1777 BEGIN 1778 DECLARE result INT DEFAULT 0; #声明 1779 SELECT COUNT(*) INTO result #赋值 1780 FROM admin ad 1781 WHERE ad.username=username AND ad.password = PASSWORD; 1782 1783 SELECT IF(result=0,'失败','成功') "结果"; #使用 1784 1785 END $ 1786 1787 ##out列表 1788 #案例:创建存储过程实现:根据女神名返回对应的男生名 1789 CREATE PROCEDURE myp4(IN beautyname VARCHAR(20),OUT boyname VARCHAR(20)) 1790 BEGIN 1791 SELECT bo.boyname INTO boyname 1792 FROM boys bo JOIN beauty b 1793 ON bo.id = b.boyfriend_id 1794 WHERE b.name=beautyname; 1795 END $ 1796 1797 CALL myp4('柳岩',@bname)$ 1798 SELECT @bname$ 1799 1800 #案例:创建存储过程实现:根据女神名返回对应的男生名和魅力值 1801 CREATE PROCEDURE myp5(IN beautyname VARCHAR(20),OUT boyname VARCHAR(20), 1802 OUT userCP VARCHAR(20)) 1803 BEGIN 1804 SELECT bo.boyname ,bo.usercp INTO boyname ,usercp #赋值 1805 FROM boys bo JOIN beauty b 1806 ON bo.id = b.boyfriend_id 1807 WHERE b.name=beautyname; 1808 END $ 1809 /* 1810 set @name='a'$ 1811 set @charm='b'$ 省略了声明 1812 */ 1813 CALL myp5('柳岩',@name,@charm)$ #相当于省去了声明 1814 SELECT @name,@charm$ #调用 1815 1816 ##inout列表 1817 #案例:返回a,b值的二倍 1818 CREATE PROCEDURE myp6(INOUT a INT,INOUT b INT) 1819 BEGIN 1820 SET a=a*2; #赋值 1821 SET b=b*2; 1822 END $ 1823 SET @aa=1$ #声明 1824 SET @bb=2$ 1825 CALL myp6(@aa,@bb)$ 1826 SELECT @aa,@bb$ #调用 1827 1828 ##课后案例 1829 #存储过程实现传入用户名密码,插入admin 1830 CREATE PROCEDURE p_insert(IN username VARCHAR(20), IN PASSWORD VARCHAR(20)) 1831 BEGIN 1832 INSERT INTO admin(username,PASSWORD) VALUES(username,PASSWORD); 1833 END $ 1834 CALL p_insert('yb','122103')$ 1835 SELECT * FROM admin$ 1836 #传入女神标号,返回姓名电话 1837 CREATE PROCEDURE p_inf(IN id INT,OUT NAME VARCHAR(50), OUT phone VARCHAR(11)) 1838 BEGIN 1839 SELECT b.name,b.phone INTO NAME,phone #注意要赋值 1840 FROM beauty b 1841 WHERE b.id=id; 1842 END $ 1843 CALL p_inf(2,@bname,@bphone)$ #省去声明 1844 SELECT @bname ,@bphone$ #调用 1845 1846 #传入两个女生生日日期,然后返回大小 1847 CREATE PROCEDURE myp7(IN date1 DATE,IN date2 DATE,OUT result INT) 1848 BEGIN 1849 SELECT DATEDIFF(date1,date2) INTO result; 1850 END $ 1851 CALL myp7('1994-09-10',DATE(NOW()),@result)$ 1852 SELECT @result$ 1853 1854 #传入一个日期类型的日期,输出为**年**月**日格式 1855 CREATE PROCEDURE myp8(IN nor_date DATETIME,OUT for_date VARCHAR(20)) 1856 BEGIN 1857 SELECT DATE_FORMAT(nor_date,'%Y年%m月%d日') INTO for_date; 1858 END $ 1859 CALL myp8(DATE(NOW()),@fd)$ 1860 SELECT @fd$ 1861 1862 #输入 小昭,返回 小昭 and 张无忌 1863 CREATE PROCEDURE myp9(IN beautyname VARCHAR(20),OUT information VARCHAR(50)) 1864 BEGIN 1865 SELECT CONCAT(beautyname,'and',IFNULL(bo.boyname,'null')) INTO information 1866 FROM boys bo ,beauty b 1867 WHERE b.boyfriend_id=bo.id 1868 AND b.name=beautyname; 1869 END $ 1870 CALL myp9('柳岩',@inf)$ 1871 SELECT @inf$ 1872 1873 #传入条目数和起始索引,查询beauty表记录, 1874 CREATE PROCEDURE myp10(IN offsett INT,IN increment INT) 1875 BEGIN 1876 SELECT * FROM beauty 1877 LIMIT offsett,increment; 1878 END$ 1879 1880 CALL myp10(3,5)$#从第3条记录开始,显示5条 1881 1882 1883 #删除储存过程 1884 DROP PROCEDURE myp7; #只能一个一个的删 1885 #查看储存过程 1886 SHOW CREATE PROCEDURE myp6\G;#在dos执行 1887 1888 1889 ##函数 1890 /* 1891 定义:一组预先编译好的SQL语句集合 1892 1893 区别:存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、更新 1894 函数:有且仅有1个返回值,适合做处理数据后返回一个结果 1895 */ 1896 /* 1897 一、创建语法: 1898 create function 函数名(参数列表) returns 返回类型 1899 begin 1900 函数体; 1901 return ; 1902 end $ 1903 1904 注意:1参数列表 包含 (无参数模式) 参数名 参数类型 1905 2函数体肯定有return语句,如果没有会报错 1906 3函数体中仅有一句话,则可以省略begin和end 1907 4使用delimiter语句设置结束标记 1908 1909 二、调用语法 1910 1911 select 函数名(参数列表) 1912 */ 1913 1914 #--------------------------函数案例演示------------------------ 1915 #1 无参有返回 案例 :返回公司的员工个数 1916 USE myemployees; 1917 CREATE FUNCTION myf1() RETURNS INT 1918 BEGIN 1919 DECLARE c INT ; #声明 1920 SELECT COUNT(*) INTO c #赋值 1921 FROM employees; 1922 RETURN c; #调用 1923 END $ 1924 SELECT myf1()$ 1925 1926 #2有参有返回 1927 #案例:根据员工名返回工资 1928 CREATE FUNCTION myf2( ename VARCHAR(20)) RETURNS INT 1929 BEGIN 1930 DECLARE s INT; 1931 SELECT salary INTO s 1932 FROM employees e 1933 WHERE e.last_name=ename; 1934 RETURN s; 1935 END $ 1936 SELECT myf2('chen')$ 1937 1938 #根据部门名返回该部门平均工资 1939 CREATE FUNCTION myf3( dname VARCHAR(20)) RETURNS INT 1940 BEGIN 1941 SET @s=0; 1942 SELECT AVG(e.salary) INTO @s 1943 FROM employees e JOIN departments d 1944 ON e.department_id = d.department_id 1945 WHERE d.department_name = dname; 1946 RETURN @s; 1947 END $ 1948 SELECT myf3('IT')$ 1949 1950 #案例 :传入两个float ,返回二者之和 1951 CREATE FUNCTION mysum(a FLOAT ,b FLOAT) RETURNS FLOAT 1952 BEGIN 1953 DECLARE absum FLOAT; 1954 SELECT a+b INTO absum; 1955 RETURN absum; 1956 END $ 1957 #查看、删除函数 1958 SHOW CREATE FUNCTION myf3\G; #dos 1959 DROP FUNCTION myf3; 1960 1961 ##流程控制 ——---------------------------------------------- 1962 /* 1963 顺序、分支、循环 1964 */ 1965 #一、 分支 1966 #if(条件,ture,false) 1967 #case 1968 /* 1969 1、等值判断 1970 1971 case 字段 1972 when 值1 then 返回值1 1973 when 值2 then 返回值2 1974 ... 1975 else 返回值3 1976 end 1977 1978 2、 条件判断 1979 case 1980 when 条件1 then 返回值1 1981 when 条件2 then 返回值2 1982 ... 1983 else 返回值3 1984 end 1985 -----可以和select 、update 搭配,case返回的是 返回值1、返回值2...,位置不限------------ 1986 1987 1988 3、case可以单独使用,只能放在begin end中 1989 case 字段 1990 when 判断条件1 then 语句1; 1991 when 判断条件2 then 语句2; 1992 ... 1993 else 语句3; 1994 end case; 1995 */ 1996 1997 #案例 1998 CREATE PROCEDURE grade_level(IN grade INT) 1999 BEGIN 2000 CASE 2001 WHEN 90< grade AND grade <= 100 THEN SELECT 'A' ; 2002 WHEN 80< grade AND grade <=90 THEN SELECT 'B' ; 2003 WHEN 70< grade AND grade <=80 THEN SELECT 'C' ; 2004 ELSE SELECT 'D' ; 2005 END CASE; 2006 END $ 2007 CALL grade_level(98)$ 2008 2009 #if 多重分支,只能用在begin end中 2010 /* 2011 if 条件1 then 语句1; 2012 elseif 条件2 then 语句2; 2013 ... 2014 ELSE 语句n; 2015 end if; 2016 */ 2017 #传入成绩,显示等级 2018 CREATE FUNCTION grade_level( grade INT) RETURNS CHAR 2019 BEGIN 2020 IF grade>90 AND grade <= 100 THEN RETURN 'A'; 2021 ELSEIF grade >80 THEN RETURN 'B'; 2022 ELSE RETURN 'c'; 2023 END IF; 2024 END$ 2025 2026 ##循环结构 2027 /* 2028 分类:while 、 loop 、 repeat 2029 2030 循环控制 : 2031 2032 iterate ,结束本次循环,继续进行下一次 2033 leave ,跳出,结束当前循环 2034 出现循环控制时,必须给循环结构添加名称 2035 */ 2036 2037 #1,while 2038 /* 2039 【标签】while 循环条件 do 2040 循环体 2041 end while 【标签】; 2042 */ 2043 2044 #2,loop 2045 /* 2046 【标签】loop 2047 循环体 2048 end loop 【标签】; 2049 2050 可以模拟简单的死循环 2051 2052 */ 2053 2054 #3,repeat 2055 /* 2056 【标签】repreat 2057 循环体 2058 until 结束循环体的条件 2059 end repeat 【标签】; 2060 */ 2061 2062 /* 2063 loop一般实现简单死循环 2064 while先判断后执行 2065 repeat先执行后判断,无条件至少执行一次 2066 */ 2067 #案例,根据次数插入到admin表中多条记录 2068 CREATE PROCEDURE p_while1(IN insertcount INT) 2069 BEGIN 2070 DECLARE i INT DEFAULT 1; 2071 WHILE i<insertcount DO 2072 INSERT INTO admin(`username`,`password`) 2073 VALUES(CONCAT('rose',i),'123'); 2074 SET i=i+1; 2075 END WHILE ; 2076 END$ 2077 CALL p_while1(50)$ 2078 2079 #案例,根据次数插入到admin表中多条记录,到20次就停止 2080 CREATE PROCEDURE p_while2(IN insertcount INT) 2081 BEGIN 2082 SET @i=1; 2083 a:WHILE @i<insertcount DO 2084 INSERT INTO admin(`username`,`password`) 2085 VALUES(CONCAT('xiaohu',@i),'0000'); 2086 IF @i>=20 THEN LEAVE a; 2087 END IF ; 2088 SET @i=@i+1; 2089 END WHILE a; 2090 END$ 2091 #案例,根据次数插入到admin表中多条记录,结尾为偶数 2092 2093 CREATE PROCEDURE p_while3(IN insertcount INT) 2094 BEGIN 2095 SET @i=0; 2096 a:WHILE @i<insertcount DO 2097 INSERT INTO admin(`username`,`password`) 2098 VALUES(CONCAT('xiaohu',@i),'0000'); 2099 SET @i=@i+2; 2100 END WHILE a; 2101 END$ 2102 2103 CREATE PROCEDURE p_while4(IN insertcount INT) 2104 BEGIN 2105 SET @i=1; 2106 a :WHILE @i<insertcount DO 2107 SET @i=@i+1; 2108 IF MOD(@i,2) !=0 THEN ITERATE a; 2109 END IF; 2110 INSERT INTO admin(`username`,`password`) 2111 VALUES(CONCAT('ts',@i),'6666'); 2112 END WHILE a ; 2113 END $ 2114 2115 ####高级sql 2116 /*GA generally available; 2117 2118 ##字符集 2119 delimiter ; 2120 show variables like '%char%'; 2121 2122 #插件式的存储引擎,将查询处理和其他的系统任务以及数据的存储提取相分离 2123 2124 mysql 分四层 2125 1连接层:与其他语言的链接,如Perl、Python 2126 2服务层:mysql查询,内部优化 2127 3引擎层:可拔插的引擎,innoDB、myISAM 2128 4存储层:硬件 2129 2130 #查看引擎 2131 show engines; 2132 show variables like '%engine%'; 2133 2134 #sql性能下降的原因 2135 1查询语句写的烂 2136 2索引失效(单值、复合) 2137 3关联查询join太多 2138 4服务器调优及各个参数设置(缓冲、线程数) 2139 2140 2141 */ 2142 ##索引 :是帮助提高mysql高效获取数据的【【 数据结构】】 2143 /* 2144 *********排好序的快速查找数据结构************* 2145 2146 数据本身之外,数据库还维护着一个满足特定查找算法的【数据结构】 2147 这些数据结构以某种方式指向数据,这样就可以在这些数据的基础上实现 2148 高级查找算法,这种数据结构就是索引。 2149 2150 索引往往以索引文件的形式存储在磁盘上 2151 2152 索引往往指的是B数(多路搜索树)结构组织的索引 2153 2154 聚集索引、全文索引、复合索引、前缀索引、唯一索引默认都是使用B+树索引,统称索引。 2155 2156 出了B+树类型,还有哈希索引(hash index) 2157 2158 索引的优劣 2159 优势: 提高数据检索的效率,降低数据库IO的成本(input and output) 2160 降低数据排序成本,降低了CPU的消耗 2161 劣势: 提高查询速度的同时,降低了更新表的速度(增删改时,索引也会发生变化) 2162 数据量较大,需要花时间研究建立最优秀的索引 2163 2164 索引分类: 2165 单值索引:一个索引只包含单个列,一个表可以有多个单列索引(银行查卡号,ID卡等) 2166 一个表最好不超5个单列索引 2167 唯一索引:索引列的值必须唯一,但允许有空值 2168 复合索引:一个索引包含多个列 2169 全文索引: 2170 2171 2172 ##索引的结构:类似于二叉树一样 2173 树的宽度又数据量决定,查询的速度由树的高度决定。 2174 判断次数(IO次数)==树的高度 2175 2176 ##什么情况适合建索引 2177 1主键自动建立唯一索引 2178 2频繁作为查询条件的字段 2179 3与其他表关联字段,如外键 应该建立索引 2180 4频繁更新的字段不适合建索引 2181 5where中用不到的字段不建索引 2182 6尽量组合索引 2183 7查询中排序的字段(若排序的字段多个,复合索引按照排序中的多个字段顺序建立) 2184 8统计或分组字段(group by和索引有关) 2185 ##什么情况不适合建索引 2186 1表字段太少(3百万以下) 2187 2经常增删改的表 2188 3数据列包含太多重复数据(国籍) 2189 2190 2191 ##性能查询 2192 用法 :explain sql语句; 2193 作用 : 1表的读取顺序 id 2194 2数据读取操作的操作类型 select_type 2195 3哪些索引可以使用 2196 4是哪索引被实际使用 2197 5表之间的引用 2198 6每张表有多少行被优化器查询 2199 2200 id、select_type、table、type、possible_key、key_len、ref、rows、extra 2201 2202 id :id相同时,table从上往下执行;存在子查询时,id不同,id值越大,越先执行。 2203 表子查询的select_type值为derived; 2204 select_type:SIMPLE \ PRIMARY \ SUBQUERY \ DERIVED \ UNION \ UNION RESULT 2205 SIMPLE : 不包含子查询和union 2206 PRIMARY:主查询,最外层 ,最后执行 2207 SUBQUERY:子查询 2208 DERIVED:表子查询 2209 UNION:union后面的表的s_t为union 2210 UNION RESULT:从union表获取结果的select 2211 table: 显示这一张行数据是关于哪张表的 2212 type: All \ index \ range \ ref \ eq_ref \ const,system \ Null 2213 显示查询使用了何种类型,由好到坏依次为: 2214 system>const>eq_ref>ref>range>index>All**************** 2215 ----------------------------------------------------------------- 2216 system:系统表,只有一行数据,const的特例,忽视掉 2217 const:表示通过索引一次就找到了,用于比较primary和unique索引 2218 因为只匹配一行数据,如where查主键的一个值 2219 eq_ref:唯一性索引扫描,对于每一个索引键,表中只有一条记录与之匹配 2220 explain select * from e ,d where e.id=d.id; 2221 #e.id的每个值在d.id中只出现一次 2222 ???ref:非唯一性索引扫描,返回匹配某个单独值的所有行(符合条件的多行) 2223 explain select * from employees where job_id='AD_VP'; 2224 range:只检索给定范围的行使用一个索引来选择行,可以列显示使用哪个索引 2225 between and > < in 2226 explain select * from employees where `employee_id` between 100 and 105; 2227 index:full index scan.与all的区别在于index只遍历索引数 2228 explain select `employee_id` from employees; 2229 full:遍历全表 2230 2231 ********一般要求出现All以后的百万级查询,必须优化。一般到range,更好为ref 2232 2233 possible_keys:显示可能应用在这张表的索引,一个或者多个(但不一定被查询实际使用) 2234 key:实际使用的索引 【查询中若使用了覆盖索引,则该索引仅出现在key列表中】 2235 【覆盖索引:用c1、c2建索引,查询为select c1,c2 from ..;】 2236 key_len:索引中使用的字节数,可通过该值计算 查询中使用的索引的长度。在不损失精度 2237 的情况下,【长度越短越好】。该值为索引字段的最大可能长度,【并非实际使用长度】 2238 ??? 即key_len是根据表计算而得,不是通过表内检索出来的 2239 ref:显示索引的哪一列被使用了,如果可能的话,【是一个常数】 2240 rows:根据 表统计信息 及索引选用情况,大致估算出找到所需记录要读取的行数,越小越好 2241 extract:包含不合适在其他列中显示但十分重要的额外信息; 2242 #using filesort:没有用索引进行排序,使用了一个外部索引【九死一生】 2243 假设假设索引为ind_t_a_c_b。 2244 select * from table t where t.a='*' order by t.c;则为using filesort 2245 select * from table t where t.a='*' order by t.b;则不为using filesort 2246 select * from table t where t.a='*' order by t.b,t.c;也不为using filesort 2247 #using temporary 使用了临时表保存中间结果,MYsql对查询结果排序时使用临时表 2248 常见于order by 和 group by【十死无生】 2249 #using index 查询中使用了覆盖索引,【效率不错】 2250 同时出现了using where 表明索引被用来执行索引键值的查找(where 后面的列被用于建索引) 2251 没出现using where表明索引中的列只用来select,没进行where 2252 #using where 使用了where 2253 #using join buffer 使用了连接缓存,配置文件里的using buffer调大 2254 #impossible where :where子句的值总是false,不能用来获取任何元组 2255 #selec table optimized away:在没有group by子句的情况下,基于索引优化min/max 2256 #distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样的动作 2257 2258 2259 */ 2260 EXPLAIN 2261 SELECT id FROM( 2262 SELECT a.id FROM admin a 2263 UNION 2264 SELECT b.id FROM beauty b) c ; 2265 EXPLAIN 2266 SELECT a.id FROM admin a 2267 UNION 2268 SELECT b.id FROM beauty b; 2269 EXPLAIN SELECT * FROM admin ORDER BY PASSWORD; 2270 2271 /* 2272 索引优化 2273 2274 */ 2275 ##案例1 单表索引优化 2276 #category为1,comments>1,views最多的article_id 2277 USE test; 2278 CREATE TABLE IF NOT EXISTS article( 2279 id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 2280 author_id INT(10) UNSIGNED NOT NULL, 2281 categoryid INT(10) UNSIGNED NOT NULL, 2282 views INT(10) UNSIGNED NOT NULL, 2283 comments INT(10) UNSIGNED NOT NULL, 2284 title VARBINARY(255) NOT NULL, 2285 content TEXT NOT NULL 2286 ); 2287 2288 INSERT INTO article(`author_id`,`categoryid`,`views`,`comments`,`title`,`content`) 2289 VALUES 2290 (1,1,1,1,'1','1'), 2291 (2,2,2,2,'2','2'), 2292 (3,3,3,3,'3','3'), 2293 (4,4,4,4,'4','4'); 2294 #情况一:无索引。!type为all,extra提示using filesort 2295 EXPLAIN SELECT * FROM article WHERE categoryid =1 AND comments >1 2296 ORDER BY views DESC LIMIT 1; 2297 #情况二:按序建索引ccv.用到了索引,type为range,但是仍使用了文件内排序 2298 #原因为comments为范围查询,sql无法利用索引再对后面的views进行检索。 2299 #即range类型查询字段后面的索引无效 2300 CREATE INDEX inx_article_ccv ON article(categoryid,comments,views); 2301 EXPLAIN SELECT * FROM article WHERE categoryid =1 AND comments >1 2302 ORDER BY views DESC LIMIT 1; 2303 #情况三:符合索引ca_v,type为ref,无文件内排序 2304 DROP INDEX inx_article_ccv ON article; 2305 CREATE INDEX inx_article_cv ON article(categoryid,views); 2306 EXPLAIN SELECT * FROM article WHERE categoryid =1 AND comments >1 2307 ORDER BY views DESC LIMIT 1; 2308 ##案例2:两表索引优化,左拼给右表加索引。 2309 USE myemployees; 2310 EXPLAIN SELECT * FROM employees e LEFT JOIN departments d 2311 ON e.`department_id`=d.`department_id`; 2312 SHOW INDEX FROM `departments`; 2313 ##案例3:三表连接,用小表驱动大表,索引建立在left 或 right 后面的 2314 2315 2316 ##索引失效的原因: 2317 /* 2318 1全职匹配我的最爱 2319 2320 2最佳左前缀法则******** 2321 复合索引要遵守该法则,查询应该从索引的最左前列开始,并且不跳过索引的列 2322 create index stu_1_2_3 on student(`studentno`,`studentname`,`loginpwd`); 2323 explain select * from student where studentno='S001' and studentname = '张三封' and `loginpwd`='8888'; 2324 explain select * from student where studentno='S001' and loginpwd = '8888'; 2325 explain select * from student where loginpwd = '8888';##第一个字段不能丢失 2326 2327 3不在索引列上做任何操作(计算、函数、(自动或者手动)的类型转换),导致索引失效,全表扫描 2328 2329 4储存引擎不能使用索引中范围条件右边的列 2330 create index table.a_b_c on table(a,b,c) 2331 select * from table where a='' and b>X and c=''; #用不到c,但是 2332 select * from table where a='' and b like 'xx%' and c='';#能用到c 2333 2334 5尽量使用覆盖索引 2335 2336 6mysql在使用非等于时(> < !=),无法使用索引,全表扫描 2337 2338 7is null ,is not null 也无法使用索引 2339 2340 8like以通配符开始,mysql无法使用索引,全表扫描, 2341 比如select * ...like '%xx'不推荐,而like 'xx%'则使用了索引,type为range 2342 若使用like '%xx%',需要使用覆盖索引, 2343 即索引包含name时,select name ... like '%xx%'; 2344 #select使用*或者非索引列字段也不行 2345 2346 like 'kk%',虽然也是range,但是与>x 不同, 2347 like后面的等值条件还能用(显示在len上), >x后面的则通通失效 2348 2349 9字符串不加单引号,mysql无法使用索引,全表扫描 2350 2351 10少用or,用or连接时索引会失效 2352 2353 总结: 2354 2355 列只和建索引的书写顺序有关:比如index 123,where 1='' and 2='' and 3='' 2356 ===where 2='' and 3='' and 1='' 2357 where 1='' and 2> and 3= 2358 ==where 1='' and 3= and 2> 2359 where有order,group时 :where 1= and 3= order by 2 2360 ==where 1= and order by 2 2361 ≈where 1= order by 2,3 2362 但是 where 1= order by 3,2 (出现内排序,group出现temporary) 2363 但是where 1= and 2= order by 3,2无内排序,因为2定值了 2364 2365 但是 where 1= and 2= order by 3 2366 !==where 1= order by 3(出现内排序using filesort) 2367 2368 范围查询与order by结合 2369 index 12 2370 where 1> order by 1 优 2371 where 1> order by 1,2 优 2372 where 1= order by 2 优 2373 where 1> order by 2 内排序 (理解索引的内涵) 2374 where 1> order by 2,1 内排序 (排好序 的快速查找数据结构) 2375 order by a acs,b desc,内排序(order by 默认升序,同升同降无内排序) 2376 2377 group by :同order by,但能用where就不用having 2378 2379 提高order by 的方法: 2380 1 使用order by大忌使用select * ,应该只查询需要的字段 2381 1.1当查询的字段的大小总和<max_length_for_sort_data而且排序字段不是 2382 text/BLOB时,会使用改进算法--单路排序,否则使用对路排序,速度慢 2383 1.2单路多路都可能超过sort_buffer的容量(单路可能性更大),超出后会创建temporary,导致慢速 2384 2385 2尝试提高sort_buffer_size 2386 3尝试提高max_length_for_sort_data,但是设置太高,容易超过sort_buffer_size 2387 2388 2389 2390 口诀: 2391 全职匹配我最爱,最左点缀要遵守 2392 带头大哥不能死,中间兄弟不能断 2393 索引列上少计算,范围之后全失效 2394 like百分写最右,覆盖索引不写星 2395 不等空值还有or,索引失效要少用 2396 var引号不可丢 ,SQL高级也不难 2397 */ 2398 2399 /*查询截取分析 2400 2401 1至少跑一天,观察,看看生产的慢sql情况 2402 2403 2开启慢查询日志,设置阈值:比如超过5秒的就是慢sql,并将其抓取出来 2404 2405 3explain+慢sql分析 2406 2407 4show profile 2408 2409 5运维经理或DBA进行数据库服务器的参数调优 2410 2411 总结: 1慢查询的开启并捕获 2412 2explain+慢sql分析 2413 3show profile查询sql在MySQL服务器里面的执行细节和生命周期情况 2414 4sql数据服务器的参数调优 2415 2416 理解小表驱动大表: 2417 2418 A表数量>>B表 2419 当:【select * from a where a.id in (select id from b)】as WAYIN 2420 的执行顺序为: 2421 1 select id from b 2422 2 select * from a where a.id=b.id 2423 此时的执行效率 in> exists 2424 2425 A表数量<<B表 2426 当:【select * from a where exists (select 1 from b where a.id =b.id)】as WAYEX 2427 的执行顺序为 2428 1 select * from a 2429 2 select id from a.id=b.id 2430 此时的执行效率 exists>in 2431 2432 【exists语法为: 2433 exists子查询中会忽略的select后面的查询列表,所以可以写1 ,'x'等常量值 2434 2435 1 先查出主查询的全部数据(小表), 2436 2 然后根据子查询(大表)得到的布尔向量决定小表数据的去留】 2437 2438 ***总结:小表驱动大表时,即A表<<B表,使用WAYEX。 2439 2440 */ 2441 2442 /*慢查询日志 2443 show variables like '%slow_query%'; 2444 2445 set global slow_query_log =1 ;#开启慢查询日志 2446 2447 show variables like '%long_query_time%';#默认时间>10s为慢sql 2448 2449 set global long_query_time=3;#设置阈值为3,查看该值需在新会话查看,非新查询编辑器 2450 set global slow_query_log_file = 'slow.log';#设置慢查日志的文件位置 2451 2452 select sleep(4); #若执行超过阈值的sql会在慢查询中显示 2453 2454 show global status like '%show_queries%';#显示当前系统中较慢的sql 条数 2455 2456 */ 2457 2458 /*show profile 2459 show variables like '%profiling%'; 2460 2461 set profiling = on; 2462 2463 show profiles; 2464 2465 show profile cpu, block io for query 17;#一条sql内部执行的完整生命周期 2466 2467 #如果status出现以下条目,降低速度 2468 1 coverting HEAP to MyISAM :查询结果太大,内存不够,往磁盘上搬了 2469 2 creating tpm table :创建临时表,[拷贝数据到临时表][用完再删除] 2470 3 cooying to tmp table on disk :把内存中临时表复制到磁盘。危险!! 2471 4 locked 2472 */ 2473 2474 /*全局查询日志:#不要在生产环境开启该功能 2475 2476 set global general_log ; 2477 set global log_output='TABLE'; 2478 select * from my.general_log; 2479 2480 */ 2481 2482 /*数据库锁理论 2483 锁是计算机协调多个进程或线程并发访问某一资源的机制 2484 2485 在数据库锁中,除传统的计算资源(CPU,RAM,IO)的征用以外,数据也是一种供许多用户共享的资源。 2486 如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库 2487 并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。 2488 2489 表锁分类: 2490 #从对数据操作的类型: 2491 1读锁(共享锁):针对同一份数据,多个读操作可以同时进行,不会互相影响 2492 (会话1给表1上读锁,能读表1,不能改表1,不能读表2) 2493 (会话2 能读表1,改表1阻塞,能读表2) 2494 2写锁(排它锁):当前写锁没有完成之前,它会阻断其他写锁和读锁 2495 (会话1给表1上写锁,能读表1, 能改表1, 不能读表2) 2496 (会话2能读表2,读表1发生阻塞,改表1更慢) 2497 总结:读锁阻塞改表,写锁阻塞读写 2498 show open tables; #显示没上锁的表 2499 lock table 表1 read, 表2 write; #表1读锁,表2写锁 2500 unlock tables; #解锁所有的表 2501 show status like 'table%'; 2502 2503 行锁:只在事务中,对行增删改时,导致某一行锁定,另一会话阻塞增删改 2504 行锁变表锁:varchar类型的 值为数字的 字段,没加引号,导致该列都被行锁,变成表锁 2505 2506 set autocommit=0; 2507 select * from table where id=x for update;#强制锁定一行 2508 commit;#直到会话1结束,会话2才能读、写 2509 */ 2510 DELIMITER ;
Valar morghulis