diff --git "a/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21027\346\227\245\350\247\246\345\217\221\345\231\250.md" "b/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21027\346\227\245\350\247\246\345\217\221\345\231\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..8fd1907fc8930a1d4bd81b5fb8684e935d18b54b --- /dev/null +++ "b/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21027\346\227\245\350\247\246\345\217\221\345\231\250.md" @@ -0,0 +1,56 @@ +**触发器**( trigger )是作为**对数据库修改的连带效果**而**由系统自动执行**的一条语句。 + + + +12. SQL 触发器 +MySQL的触发器和存储过程一样,都是嵌入到MySQL的一段程序。触发器是由事件来触发某个操作,这些事件包括INSERT、UPDATAE和DELETE语句。如果定义了触发程序,当数据库执行这些语句的时候就会激发触发器执行相应的操作,触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象。 + +12. 1 创建触发器 +触发器(trigger)是一个特殊的存储过程,不同的是,执行存储过程要使用CALL语句来调用,而触发器的执行不需要使用CALL语句来调用,也不需要手工启动,只要当一个预定义的事件发生的时候,就会被MySQL自动调用。 + +其中,trigger_name表示触发器名称,用户自行指定;trigger_time表示触发时机,可以指定为before或after;trigger_event表示触发事件,包括INSERT、UPDATE和DELETE;tbl_name表示建立触发器的表名,即在哪张表上建立触发器;trigger_stmt是触发器执行语句。 + +## 2 查看触发器 + +- **SHOW TRIGGERS语句** + +```sql +show triggers; +1 +``` + + + + 删除触发器 + +使用DROP TRIGGER语句可以删除MySQL中已经定义的触发器,删除触发器语句的基本语法格式如下 + + + +三、使用触发器 + +1. CREATE TRIGGER newProduct03 AFTER INSERT ON products +2. FOR EACH ROW SELECT NEW.prod_id INTO @info; + -- INSERT INTO products(prod_id,...) VALUES(123,...); + -- SELECT @info + + + +DELETE(删除)触发器 + +``` +DELIMITER // +CREATE TRIGGER productsDeleteInfo AFTER DELETE ON products +FOR EACH ROW +BEGIN + INSERT INTO `productsin`(`prod_id`, `vend_id`, `prod_name`, `prod_price`, `prod_desc`) + VALUES(OLD.prod_id, OLD.vend_id, OLD.prod_name, OLD.prod_price, OLD.prod_desc); +END// +DELIMITER ; +DELETE FROM products WHERE prod_id = 'RYL01'; +``` + +当对products表执行删除操作后,会将删除的数据写入productsin表中。(productsin表要存在) + +OLD代表删除前的数据,由于OLD只读不能修改,所以也代表删除后的数据。 + diff --git "a/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21028\346\227\245\350\241\214\350\275\254\345\210\227\357\274\214\345\210\227\350\275\254\350\241\214.md" "b/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21028\346\227\245\350\241\214\350\275\254\345\210\227\357\274\214\345\210\227\350\275\254\350\241\214.md" new file mode 100644 index 0000000000000000000000000000000000000000..92d7126ccff42f741dd3df190b38efc73682dcd6 --- /dev/null +++ "b/32\350\203\241\346\261\237\351\233\204/\347\254\224\350\256\260/9\346\234\21028\346\227\245\350\241\214\350\275\254\345\210\227\357\274\214\345\210\227\350\275\254\350\241\214.md" @@ -0,0 +1,174 @@ +## 行转列 + +即将原本同一列下多行的不同内容作为多个字段,输出对应内容。 + +-- 创建测试表 学习成绩统计表 +CREATE TABLE ScoreStatistics +( + UserName NVARCHAR(20), --学生姓名 + SubjectName NVARCHAR(30), --科目名称 + Score FLOAT, --成绩 +) +-- 插入测试数据 +INSERT INTO ScoreStatistics SELECT '小王', '语文', 100 +INSERT INTO ScoreStatistics SELECT '小王', '数学', 90.5 +INSERT INTO ScoreStatistics SELECT '小王', '英语', 88 +INSERT INTO ScoreStatistics SELECT '小王', '历史', 65 +INSERT INTO ScoreStatistics SELECT '小李', '语文', 81 +INSERT INTO ScoreStatistics SELECT '小李', '数学', 99 +INSERT INTO ScoreStatistics SELECT '小李', '英语', 95 +INSERT INTO ScoreStatistics SELECT '小李', '历史', 90 +INSERT INTO ScoreStatistics SELECT '小刘', '语文', 90 +INSERT INTO ScoreStatistics SELECT '小刘', '数学', 85 +INSERT INTO ScoreStatistics SELECT '小刘', '英语', 59 +INSERT INTO ScoreStatistics SELECT '小刘', '历史', 98 +-- 传统写法 +select UserName, + max(case SubjectName when '语文' then Score else 0 end)语文, + max(case SubjectName when '数学'then Score else 0 end)数学, + max(case SubjectName when '英语'then Score else 0 end)英语, + max(case SubjectName when '历史'then Score else 0 end)历史 +from ScoreStatistics +group by UserName +-- PIVOT 写法更简洁 +SELECT * FROM ScoreStatistics +AS P +PIVOT +( + SUM(Score/*行转列后 列的值*/) FOR + p.SubjectName/*需要行转列的列*/ IN ([语文],[数学],[英语],历史 + /*列的值*/) +) AS T +-- order by 语文 desc 具体科目排序 +-- order by username desc -- 姓名排序 +-- 动态拼接列的示例 +DECLARE @sql_str VARCHAR(8000); -- 要执行的sql +--拿到数值列 [历史],[数学],[英语],[语文] +DECLARE @sql_col VARCHAR(8000); +SELECT @sql_col = ISNULL(@sql_col + ',','') ++ QUOTENAME(SubjectName) +FROM ScoreStatistics GROUP BY SubjectName; +print(@sql_col); -- 打印数值列,不必需 +SET @sql_str = ' +SELECT * FROM ( +SELECT [UserName],[SubjectName],[Score] FROM [ScoreStatistics]) +p PIVOT +(SUM([Score]) FOR [SubjectName] IN ( '+ @sql_col +') ) AS pvt +ORDER BY pvt.[UserName]' +PRINT (@sql_str);--打印执行的sql +EXEC (@sql_str);-- 执行查询 + + + +### 1、使用case…when…then 进行行转列 + +``` +SELECT userid, +SUM(CASE `subject` WHEN '语文' THEN score ELSE 0 END) as '语文', +SUM(CASE `subject` WHEN '数学' THEN score ELSE 0 END) as '数学', +SUM(CASE `subject` WHEN '英语' THEN score ELSE 0 END) as '英语', +SUM(CASE `subject` WHEN '政治' THEN score ELSE 0 END) as '政治' +FROM tb_score +GROUP BY userid +``` + + + +### 2、使用IF() 进行行转列: + +``` +SELECT userid, +SUM(IF(`subject`='语文',score,0)) as '语文', +SUM(IF(`subject`='数学',score,0)) as '数学', +SUM(IF(`subject`='英语',score,0)) as '英语', +SUM(IF(`subject`='政治',score,0)) as '政治' +FROM tb_score +GROUP BY userid +``` + + + +注意点: + +(1)SUM() 是为了能够使用GROUP BY根据userid进行分组,因为每一个userid对应的subject="语文"的记录只有一条,所以SUM() 的值就等于对应那一条记录的score的值。 + +假如userid =‘001’ and subject=‘语文’ 的记录有两条,则此时SUM() 的值将会是这两条记录的和,同理,使用Max()的值将会是这两条记录里面值最大的一个。但是正常情况下,一个user对应一个subject只有一个分数,因此可以使用SUM()、MAX()、MIN()、AVG()等聚合函数都可以达到行转列的效果。 + +(2)IF(`subject`=‘语文’,score,0) 作为条件,即对所有subject='语文’的记录的score字段进行SUM()、MAX()、MIN()、AVG()操作,如果score没有值则默认为0。 + + + +### 3、利用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行,并利用 IFNULL将汇总行标题显示为Total + +``` +SELECT IFNULL(userid,'total') AS userid, +SUM(IF(`subject`='语文',score,0)) AS 语文, +SUM(IF(`subject`='数学',score,0)) AS 数学, +SUM(IF(`subject`='英语',score,0)) AS 英语, +SUM(IF(`subject`='政治',score,0)) AS 政治, +SUM(IF(`subject`='total',score,0)) AS total +FROM( + SELECT userid,IFNULL(`subject`,'total') AS `subject`,SUM(score) AS score + FROM tb_score + GROUP BY userid,`subject` + WITH ROLLUP + HAVING userid IS NOT NULL +)AS A +GROUP BY userid +WITH ROLLUP; + + + + +列转行 +建表语句: +CREATE TABLE tb_score1( + id INT(11) NOT NULL auto_increment, + userid VARCHAR(20) NOT NULL COMMENT '用户id', + cn_score DOUBLE COMMENT '语文成绩', + math_score DOUBLE COMMENT '数学成绩', + en_score DOUBLE COMMENT '英语成绩', + po_score DOUBLE COMMENT '政治成绩', + PRIMARY KEY(id) +)ENGINE = INNODB DEFAULT CHARSET = utf8; + + + + +插入数据: +INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ('001',90,92,80,0); +INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ('002',88,90,75.5,0); +INSERT INTO tb_score1(userid,cn_score,math_score,en_score,po_score) VALUES ('003',70,85,90,82); + + +查询数据表中的内容(即转换前的结果) + +SELECT * FROM tb_score1 +搞定mysql的 行转列(7种方法) 和 列转行_行转列_09 + +转换后: + +搞定mysql的 行转列(7种方法) 和 列转行_字段_10 + +本质是将userid的每个科目分数分散成一条记录显示出来。 + +直接上SQL: +SELECT userid,'语文' AS course,cn_score AS score FROM tb_score1 +UNION ALL +SELECT userid,'数学' AS course,math_score AS score FROM tb_score1 +UNION ALL +SELECT userid,'英语' AS course,en_score AS score FROM tb_score1 +UNION ALL +SELECT userid,'政治' AS course,po_score AS score FROM tb_score1 +ORDER BY userid + + +这里将每个userid对应的多个科目的成绩查出来,通过UNION ALL将结果集加起来,达到上图的效果。 + +附:UNION与UNION ALL的区别(摘) +对重复结果的处理:UNION会去掉重复记录,UNION ALL不会; +对排序的处理:UNION会排序,UNION ALL只是简单地将两个结果集合并; +效率方面的区别:因为UNION 会做去重和排序处理,因此效率比UNION ALL慢很多; + + +``` \ No newline at end of file