概述
- mysql 十一章使用数据处理函数
11.1 函数:
例子:RTrim(),Trim(), LTrim(),
11.2使用函数
处理字符串的文本函数(supper(),lower())。
数值函数
日期和时间函数
系统函数
11.2.1 文本处理函数
代码如下:select vend_name, upper(vend_name) as vend_name_upcase from django_apps_vendor order by vend_name;
upper()将文本转换为大写
常用的文本处理函数:RTrim(),Trim(), LTrim(),Upper(),Lower(),SubString(), Length(), Left(), Right(), Locate().
Soundex()函数:
select cust_name, cust_contact from django_apps_customer where cust_contact = “Y.Lie”;
把cust_contact= "Y.Lee"输入为cust_contact = "Y.Lie"结果没有数据返回
select cust_name, cust_contact from django_apps_customer where Soundex(cust_contact) = Soundex(“Y.Lie”);
使用这个函数进行搜索,它匹配所用发音类似于Y.Lie的联系名。
11.2.2 日期和时间处理函数https://wiki.jikexueyuan.com/project/mysql/useful-functions/time-functions.html
日期必须为格式yyyy-mm-dd
6月6号学习记录
1.MySQL-执行算术运算
select prod_id, quantity, item_price from orderitems where order_num = 20005;
select prod_id, quantity, item_price, quantity*item_price as expanded_price from orderitems where order_num = 20005;
quantity*item_price总的价格。
算术运算符的优先级,括号,加,减,乘,除。
如何去测试计算:
例子:select (3*2) ;
select RTrim(‘abc’);
select now();
函数:upper()转换为大写
select vend_name, upper(vend_name) as vend_name_upcase from vendors order by vend_name;
soundex()根据发音比较而不是字母比较。
select cust_name, cust_contact from customers where cust_contact = “Y.Lie”;
select cust_name, cust_contact from customers where soundex(cust_contact) = soundex(“Y.Lie”);
日期的简单查询:yyyy-mm-dd基本格式
select order_num, cust_id from orders where order_date = ‘2005-09-01’;
select order_num, cust_id from orders where date(order_date) = ‘2005-09-01’;
select cust_id, order_num from orders where date(order_date) between ‘2005-09-01’ and ‘2005-09-30’;日期范围
select cust_id, order_num from orders where year(order_date) = 2005 and month(order_date) = 9;
这个不需要记住每个月有多少天,或者不需要关心闰年2月的方法。
数值函数;:
select mod(6,3) select sqrt(8); select exp(8); select abs(-1);select cos(1);select rand();select pi()
2.mysql-汇总数据
聚集函数:运行在行组上,计算和返回单个值的函数。
确定表中的行数, 获得表中行组的数据, 找出表列的最大值,最小值和平均值。
mysql给出5个聚集函数。
AVG() 平均值 count()行数 max()最大值 min()最小值 sum()值之和
实例:select avg(prod_price) as avg_price from products;
count():
select count(*) as num_cust from customers;所用的行,忽略null
select count(cust_email) as num_cust from customers; 特定的行。不忽略null
max():
select max(prod_price) as max_price from products;
mix():
select min(prod_price) as min_price from products;
sum(): 返回指定列值的和。
select sum(quantity) as items_ordered from orderitems where order_num = 20005;求20005这个订单号,数量的和。
select sum(quantity*item_price) as items_ordered from orderitems where order_num = 20005;
求20005物品价钱的和,
select avg(distinct prod_price) as avg_price from products where vend_id = 1003;
组合聚集函数使用:select count(*) as num_items, min(prod_price) as price_min, max(prod_price) as price_max, avg(prod_price) as price_avg from products;
6月7号学习记录
一. MySQL
1.分组数据
select count(*) as num_prods from products where vend_id = 1003;
返回供应商1003提供的产品数目。
2.创建分组:group by 子句
select vend_id, count(*) as num_prods from products group by vend_id;
group by按vend_id 排序并分组数据。
group by 子句的一些规定:
<1> group by子句必须出现在where子句之后,order by子句之前。
<2> group by子句可以包含任意数目的列。
<3>在建立分组时,指定的所有列都一起计算。如果在group by子句中嵌套了分组,数据将在最后的分组上进行汇总。
<4> group by子句中列出的每个列必须是检索列或有效的表达式(但不能是聚集函数)。
如果在select中使用表达式,则必须在group by子句中指定相同的表达式。不能使用别名。
<5>除聚集函数语句外,select语句中的每个列都必须在group by子句中给出。
<6>如果分组列中具有null值,则null将作为一个分组返回。有多行null值,他们将分为一组。
- with rollup 和 coalesce
select count(*) as num_prods from products group by vend_id with rollup;
把总的行数在进行汇总, 返回null
把返回null的设置一个取代名称,语法:coalesce(a,b,c),
如果anull则选择b,bnull则选择c
select coalesce(vend_id, ‘总和:’), count(*) as num_prods from products group by vend_id with rollup;
- 过滤分组having
select cust_id, count() as orders from orders group by cust_id having count() >= 2;
先用group by子句进行分组,然后再用having子句进行过滤分组。
select vend_id, count(*) as num_prods from products where prod_price >= 10 group by vend_id; 先进行分组,找出所有符合条件的
select vend_id, count() as num_prods from products where prod_price >= 10 group by vend_id having count() >= 2;在过滤
5.分组和排序group by 和order by 结合使用
select order_num, sum(quantityitem_price) as ordertotal from orderitems group by order_num having sum(quantityitem_price) >= 50 order by ordertotal;
第一步先进行分组:
select order_num, sum(quantity*item_price) as ordertotal from orderitems group by order_num;
第二步进行分组过滤
select order_num, sum(quantityitem_price) as ordertotal from orderitems group by order_num having sum(quantityitem_price) >= 50;
最后一步:进行排序
select order_num, sum(quantityitem_price) as ordertotal from orderitems group by order_num having sum(quantityitem_price) >= 50 order by ordertotal;
6.select字句的循序
select from where gruop by having order by limit
select 要返回列或表达式,
from 从中检索数据的表, 仅在从表选择数据时使用
where 行级过滤
group by 分组说明, 仅在按组计算聚集时使用
having 组级过滤
order by 输出排序顺序
limit 要检索的行数
Django3.xx——xadmin 报错处理总结
错误1.AttributeError: module ‘django.db.models‘ has no attribute ‘FieldDoesNotExist‘
解决方法:
from django.core import exceptions
问题2:IndexError: list index out of range
解决方法:
我的解决方法:(用><分组)
将:
input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).replace(‘/><input’, ‘/>n<input’).split(‘n’) if ht != ‘’]
改为:
input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).split(‘><’) if ht != ‘’]
input_html[0] = input_html[0] + “>”
input_html[1] = “<” + input_html[1]
6月8号学习记录
1.MySQL——子查询
select 语句是SQL的查询。select语句的简单查询,从单个数据库表中检索数据的单条语句。
查询(query):任何SQL语句都是查询。但此术语一般指select语句。
SQL语句还允许创建子查询,既嵌套在其他查询中的查询。
<1> 利用子查询进行过滤
例子:假如需要列出订购物品TNT2的所有客户,应该怎么检索?
步骤:第一步:检索包含物品TNT2的所有订单的编号。
select order_num from orderitems where prod_id = “TNT2”; 返回结果为(20005, 20007)
第二步:检所具有前一步骤列出的订单编号的所有客户的ID。
select cust_id from orders where order_num in (select order_num from orderitems where prod_id = “TNT2”); 或者select cust_id from orders where order_num in (20005, 20007);返回结果为(10001, 10004)
第三部:检索前一步骤返回的所有客户ID的客户信息。
select cust_name, cust_contact from customers where cust_id in (select cust_id from orders where order_num in (select order_num from orderitems where prod_id = “TNT2”));
或者select cust_name, cust_contact from customers where cust_id in (10001, 10004);
上述的每一个步骤都可以单独作为一个查询来执行。
可以把一条select语句返回的结果用于另一条select语句的where子句。
在select语句中,子查询总是从内向外处理。
注意:in操作符作用是传递给外部查询的where子句。子查询一般与in操作符结合使用。但也可以用于测试,等于(=),不等于(!=,<>)等。
<2> 作为计算字段使用子查询,另一种子查询使用方式
select cust_name, cust_state, (select count(*) from orders where orders.cust_id = customers.cust_id) as orders from customers order by cust_name;
这里涉及到相关子查询:设计外部查询的子查询。任何时候只要列名可能有多义性,就必须使用这种语法,表名和列名由一个句点分割。
where orders.cust_id = customers.cust_id
2.python测试
11.1 测试函数
11.1.1 单元测试和测试用例
Python标准库中的模块unittest提供了代码测试工具
单元测试用于核实函数的某个方面没有问题;
测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。
对于大型项目,要实现全覆盖可能很难。
11.1.2 可通过的测试
要为函数编写测试用例,可先导入模块unittest以及要测试的函数,在创建一个继承unittest.TestCase的类。,并编写一系列方法
对函数行为的不同方面进行测试。
11.1.3 不能通过的测试
11.1.4 测试未通过怎么办
11.1.5 添加新测试
11,2 测试类
前面是针对函数的测试,那么现在就是针对类的测试。
对类进行测试可以保证所做的改进没有破坏其原有的行为。
11.2.1 各种断言方法
unittest.TestCase类中提供了很多断言方法。断言方法检查你认为应该满足的条件是否确实满足。
如果该条件满足,你对程序行为的假设就得到了确认,你就可以确信其中没有错误。
反之,Python将发生异常。
unittest 中的断言方法
- assertEquals(a,b) 核实 a==b
- assertNotEquals(a,b) 核实 a != b
- assertTrue(x) 核实 x=True
4.assertFalse(x) 核实 x=False - assertIn(item, list) 核实item 在 list中。
- assertNotIn(item, list) 核实 item 不再 list中
6月9号学习进度
1.Django-rest-fromwork遇到的问题
Django REST Framework (DRF): TypeError: register() got an unexpected keyword argument 'base_name’j
将base_name改为basename就好了
2.How to fix " AttributeError at /api/doc ‘AutoSchema’ object has no attribute ‘get_link’ " error in Django
在Settings.py下配置:
REST_FRAMEWORK = { ‘DEFAULT_SCHEMA_CLASS’: ‘rest_framework.schemas.coreapi.AutoSchema’ }
就好了。
第十六章——创建高级联结
1.使用表别名
select
concat(vend_name, ‘(’,vend_country, ‘)’)
as vend_title
from vendors
order by vend_name;
返回的数据:列别名
±-----------------------+
| vend_title |
±-----------------------+
| ACME(USA) |
| Anvils R Us(USA) |
| Furball Inc.(USA) |
| Jet Set(England) |
| Jouets Et Ours(France) |
| LT Supplies(USA) |
±-----------------------+
别名除了用于列名和计算字段外,SQL还允许给表名起别名。
这样做的理由是:缩短SQL语句; 允许在单条select语句中多次使用相同的表。
代码如下:
select cust_name, cust_contact
from customers as c, orders as o, orderitems as oi
where c.cust_id = o.cust_id
and o.order_num = oi.order_num
and prod_id = “TNT2”;
表别名:
返回的数据:±---------------±-------------+
| cust_name | cust_contact |
±---------------±-------------+
| Coyote Inc. | Y Lee |
| Yosemite Place | Y Sam |
±---------------±-------------+
可以看到,from子句中三个标全都具有别名。
表别名不仅能用于where子句,还可以用于select的列表,order by子句以及语句的其他部分。
注意:表别名只在查询执行中使用。与列别名不一样,表别名不返回客户机。
- 使用不同类型的联结
其他的联结:自联结、自然联结、外部联结
自联结:(了解)
select p1.prod_id, p1.prod_name
from products as p1, products as p2
where p1.vend_id = p2.vend_id
and p2.prod_id = “DTNTR”;
6月10号学习记录
1.flask遇到的问题
flask.cli.NoAppException: Could not import “hello”
在学习flask的时候,运行python -m flask run命令,启动程序报上面的问题
在要运行的py文件下运行,比如此处的hello.py还有上一层目录test,需要切换到hello.py的目录下,运行python -m flask run
$ export FLASK_APP = hello.py
$ export FLASK_ENV = development
$ flask run
16.2.MySQL——使用不同类型的联结
16.2.1自联结
select vend_id from products where prod_id = “DTNTR”;
select prod_id, prod_name from products where vend_id = 1003 order by prod_name;
这是通过子查询得到的。
找你使用自联结来查找?
select p1.prod_id, p1.prod_name
from products as p1, products as p2
where p1.vend_id = p2.vend_id
and p2.prod_id = ‘DTNTR’;
此查询中需要的两个表实际上是相同的表,因此products表在from子句中出现了两次。这里用表别名,p1为第一次出现的,p2为第二次出现的。按照第二个表中的prod_id过滤数据。
注意:自联结通常作为外部语句用来替代从相同的表中检索数据时使用的子查询语句。
16.2.2自然联结:排除多次出现,使每个列返回一次。
自然联结是这样一种联结,其中你只能选择那些唯一的列。
这一般是通过对表使用通配符(select *),对所有其他表的列使用明确的子集来完成的。
select c.*, o.order_num, o.order_date, oi.prod_id, oi.quantity, oi.item_price
from customers as c, orders as o, orderitems as oi
where c.cust_id = o.cust_id
and o.order_num = oi.order_num
and prod_id = ‘FB’;
从这个例子中,通配符只对第一个表使用,所有其他列明确列出,所以没有重复的列被检索出来。
外部联结:联结包含那些在相关表中没有关联行的行。
需求:每个客户下了多少订单进行计数,包括哪些没有下订单的客户。
列出所有产品以及订购数量,包括没有订购的产品。
计算平均销售规模,包括哪些至今没有下订单的客户。
代码例子:内部连接
select customers.cust_id, orders.order_num
from customers inner join orders
on customers.cust_id = orders.cust_id;
在使用outer join语法时,必须使用right或left关键字指定包括其所有行的表
(right指出的是outer join右边的表,而left指出的是outer join左边的表。)
16.2.3外部联结:
select customers.cust_id, orders.order_num
from customers left outer join orders #左外部联结
on customers.cust_id = orders.cust_id;
select customers.cust_id, orders.order_num
from customers right outer join orders #右外部联结
on customers.cust_id = orders.cust_id;
16.3使用带聚集函数的联结
select customers.cust_name, customers.cust_id, count(orders.order_num) as num_ord
from customers inner join orders
on customers.cust_id = orders.cust_id
group by customers.cust_id;
select customers.cust_name, customers.cust_id, count(orders.order_num) as num_ord
from customers left outer join orders
on customers.cust_id = orders.cust_id
group by customers.cust_id;
16.4 使用联结和联结条件
- 注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的。
2.保证使用正确的联结条件。,否则将返回不正确的数据。
3.应该总是提供联结条件,否则会得出笛卡儿积。
4.在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。
16.5小结
6月11号学习记录
1.MySQL第十七章——组合查询
17.1 组合查询
定义:允许执行多个查询(多条select语句),并将结果作为单个查询结果集返回。这些组合查询通常称为并(union)或复合查询。
有两种基本情况,其中需要使用组合查询。
1.在单个查询中从不同的表返回类似结构的数据。
2.对单个表执行多个查询,按单个查询返回数据。(这一章只介绍了这一个单个表的组合查询,但是union组合查询可以应用不同的表。)
17.2 创建组合查询
可用union操作符来组合数条SQL查询。利用union,可给出多条select语句,将他们的结果组合成单个结果集。
17.2.1使用union
使用很简单,只需要给出每条select语句,在各条语句之间放上关键字union.
代码示例:select vend_id, prod_id, prod_price from products where prod_price <= 5;
select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002);
1.使用union将这两条语句联系在一起
select vend_id, prod_id, prod_price from products where prod_price <= 5
union
select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002);
解释:这两条语句用union关键字分隔。
union只是MySQL执行两条select语句,并把输出组合成单个查询结果集。
2.使用where怎么写?
select vend_id, prod_id, prod_price from products where prod_price <= 5
or vend_id in (1001, 1002);
我们可以比较一下union和where,很显然where子句更加简单,但是对于更加复杂的过滤条件来说,或者从多个表(而不是单个表)中检索数据的情形,使用union可能会使处理更加简单。
17.2.2 union 规则。
注意几点:第一:union必须是两条或者两条以上的select语句组成,语句之间用关键字union分隔。
第二:union中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)
第三:列数据类型必须兼容。
17.2.3 包含或取消重复的行
select vend_id, prod_id, prod_price from products where prod_price <= 5;返回4行
select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002);返回5行
但使用union却返回8行,说明有一行是重复的行。所以union会将重复的行自动取消。
其实你也可以取消重复,使用union all
select vend_id, prod_id, prod_price from products where prod_price <= 5
union all
select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002);
说明:使用union all MySQL不取消重复的行。
union all 为union一种形式,他完成where子句完成不了的工作。如果确实需要每个条件的的匹配行全部出现(包括重复行),则必须使用union all而不是union。
17.2.4 对组合查询结果排序
select语句输出用order by子句排序。在用union组合查询时,只能使用一条order by子句,他必须出现在最后一条select 语句之后。
select vend_id, prod_id, prod_price from products
where prod_price <= 5
union
select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002)
order by prod_price;
2.djnago——调试和优化
12.1.1调试手段
一般情况下,有这么几种调试方法:print、logging(日志记录)和pdb(ipdb)。
1.print这种方法最简单、最直观的方法,新手上来就会用。(注意print只能用于开发阶段,上线之后代码里应该不允许存在print的调试代码。)
需要补充的是,如果需要打印json或者dict格式的数据,可以使用pprint模块的pprint函数。
import json
from pprint import pprint
pprint(json.loads(data))
2.logging模块(如果我们想要在线上收集一些数据的话,可以使用logging模块)
注意:print和logging的差别在于logging可以选择输出到文件上中还是输出到控制台上)
另外最重要的是logging可以始终保留在代码中,通过调整log的级别来决定是否打印到文件或者控制台上甚至是Sentry(异常收集系统)上。
- pdb(ipdb和bpdb)
这个调试非常重要,一定要掌握。这个调试可以跟踪程序的执行流程,观察问题的所在。
pdb提供了交互式环境,我们可以在代码中引入
import pdb
pdb.set_trace()
来让程序执行到这一行后进入pdb交互模式,进而可以像在Python shell中执行命令那样,获得到上下文所有变量的值或者更改变量的值。
关于pdb具体的使用可查看官方文档来学习。
ipdb常用的命令
h(help):帮助命令
s(step into):进入函数内部
n(next):执行下一行
b(break): b line_number打断点
cl(clear): 清除断点
c(continue): 一直执行到断点
r(return): 从当前函数返回
j(jump): j line_number,跳过代码片段,直接执行指定行号所在的代码
l(list): 列出上下文代码
a(argument): 列出传入函数所有的参数值
p/pp: print 和 pretty print打印出变量值
r(restart): 重启调试器
q(quit): 推出调试,清除所有信息
MySQL:第十八章——全文本搜索
18.1 理解全文本搜索
并非所有引擎都支持全文本搜索:MySQL支持几种基本的数据库引擎。最常使用的引擎为myisam和innodb.
现在基本上使用InnoDB。
在前面的第八章和第九章使用like和regexp来进行文本的搜索,虽然这些搜索机制比较有用,但是存在几个重要的限制。
第一个是性能方面:使用like和regexp来进行文本的搜索来进行搜索时,通常要匹配表中所有的行,但是有的数据是不需要匹配的,所以搜索起来比较耗时间。
第二个是明确控制:使用like和regexp来进行文本的搜索很难明确地控制匹配什么和不匹配什么。
第三个是智能化的结果:使用like和regexp来进行文本的搜索它们都不能提供一种智能化的选择结果的方法。
这些限制我们都可以用全文本搜索来解决。
18.2 使用全文本搜索
为了进行全文本搜索,必须索引被搜索的列。而且要随着数据的改变不断地重新索引。
在索引之后,select可与match()和against()以实际执行搜索。
18.2.1启用全文本搜索支持
一般在创建表时启用全文本搜索。
fulltext全文本搜索,定义这个之后,MySQL会自动维护该索引。在增加,更新或删除行时,索引随之自动更新。
注意:应该首先导入所有数据,然后在修改表,定义fulltext。
6月12号学习记录
18.2.2 进行全文本搜索
在索引之后,使用两个函数match()和against()执行全文本搜索,
其中match()指定被搜索的列,against()指定要使用的搜索表达式。
代码示例:
select note_text
from productnotes
where match(note_text) against(“rabbit”);
解释说明:
此select语句检索单个列note_text。由于where子句,一个全文本搜索被执行。
match(note_text)指示MySQL针对指定的列进行搜索,against(“rabbit”)指定词rabbit作为搜索文本。
注意:搜索不区分大小写;
使用完整的match()说明:传递给match()的值必须与fulltext()定义中的相同。如果指定多个列,则必须列出它们(而且次序相同)。
使用like也可以但是返回的结果不会按照排好的顺序返回。
select note_text
from productnotes
where note_text
like “%rabbit%”;
全文本搜索的一个重要的部分就是对结果排序。具有较高等级的行先返回。全文本搜索不需要加入order by子句。
下面的代码是演示排序的等级:
select note_text, match(note_text) against(“rabbit”)
as aaa
from productnotes;
这里在select而不是where子句中使用match()和against()。这使所有的行都被返回(因为没有where子句)。创建一个计算列别名为aaa,这个列包含全文本搜索出的等级值。
等级是怎么划分的?
等级是由行中词的数目、唯一词的数目、整个索引中词的总数、以及包含该词的行的数目计算出来的。
不包含改词的行等级为0,包含该词的行每行都有一个等级值,文本中词靠前的行的等级值比词靠后的等级值高。
18.2.3 使用查询扩展
查询扩展用来设法放宽所返回的全文本搜索范围的结果。
代码示例:
select note_text
from productnotes
where match(note_text) against(“anvils” with query expansion);
with query expansion查询扩张
查询扩展极大地增加了返回的行数,但这样做也增加了你实际上并不想要的行的数目。
行越多越好:表中的行越多(这些行中的文本就越多),使用查询扩展返回的结果越好。
18.2.4 布尔文本搜索
MySQL支持全文本搜索的另一种形式,叫做布尔方式(boolean mode)。
利用这只查询方式可以提供如下细节:
要匹配的词
要排斥的词(如果某行包含这个词,则不返回改行,及时它包含其他指定的词也是这样)
排列提示(指定某些词比其他词更重要,更重要的词等级更高)
表达式分组
另外一些内容;
注意:即使没有fulltext索引也可以使用(但是性能会随着数据量的增加而降低)
代码实例:
select note_text
from productnotes
where match(note_text) against(“heavy” in boolean mode);
检索包含heavy所有的行。
select note_text
from productnotes
where match(note_text) against(“heavy -rope*” in boolean mode);
解释说明:
-rope* 明确的指示mysql排除包含rope*(任何以rope开头的词,包括ropes)的行。
-
- 是两个布尔操作符,-排除一个词, * 是截断操作符(相当于一个用于结尾的通配符)。
重点知识:,
布尔操作符:+ 包含,词必须存在
- 排除与上面的相反
包含,而且增加等级值
< 包含,减少等级值
-
()把词组成子表达式
- 取消一个词的排序值
- 词尾的通配符
" " 定义一个短语
代码实例怎么使用这些布尔操作符:
1.select note_text
from productnotes
where match(note_text) against(“+rabbit +bait” in boolean mode); 包含rabbit和bait的词的行。
2.select note_text
from productnotes
where match(note_text) against(“rabbit bait” in boolean mode); 包含这两个词中的至少一个词的行。
3.select note_text
from productnotes
where match(note_text) against(‘“rabbit bait”’ in boolean mode); 匹配搜索短语rabbit bait而不是两个词。
4.select note_text
from productnotes
where match(note_text) against(“>rabbit <bait” in boolean mode); 增加前者的等级,降低后者的等级。
5.select note_text
from productnotes
where match(note_text) against(“+safe +(<combination)” in boolean mode);包含safe 和combination,降低后者的等级。
18.2.5 全文本搜索的使用说明
- 仅在MyISAM数据库引擎只支持全文本搜索。
2.忽略词中的单引号。
3.表中的行数少于三行,则全文本搜索不返回结果。
4.许多词出现的频率很高,搜索他们没有用处(返回的结果太多)。
5.在搜索全文本数据时,短词被忽略且从索引中排除。短词定义为具有三个或三个以下字符的词。
6.MySQL带有一个内建的非用词列表,这些词在索引全文本数据时总是被忽略。
7.不具有词分隔符的语言不能恰当地返回全文本搜索结果。
6月13号学习记录
MySQL——第十九章插入数据
19.1数据插入(insert)
19.2插入完整的行
INSERT INTO
customers——表名
(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) ——列名
VALUES
(null, ‘Pep E.LaPew’, ‘100 Main Street’, ‘Los Angeles’, ‘CA’, ‘90046’, ‘USA’, null, null);——列值
insert语句一般不会产生输出。有些列是null值,比如cust_id,cust_contact, cust_email
cust_id是这个表的主键,所以即使是null值它也会自动赋予一个可用的值。
其他的列如果没有值就可以为null值。
一般不要使用没有明确给出列的列表的insert语句。
不管使用哪种那种insert语法,都必须给出values的正确数目。
列可以定义为允许的null值。
在表定义中给出默认值。
如果数据的检索是最重要的,可以在insert和into之间添加关键字low_priority(优先)。指示MySQL减低insert语句的优先级。
19.3插入多个行
使用多条select语句,一次提交他们,每条语句一个分号结束。
19.4插入检索出的数据
19.5小结
第二十章——更新和删除数据(update和delete)
20.1 更新数据
我为了更新(修改)表中的数据,可使用update语句。可采用两种方式使用update.
更新表中的特定行;更新表中的所有行。
不要省略where子句。在使用update使一定要注意,因为稍不注意,就会更新表中所有的行。
update语句由三部分组成:分别是:要更新的表,列名和它们的新值,确定要更新行的过滤数据。
update
customers 要更新的表名
set 用来将新值赋给被更新的列。
cust_email = ‘elmer@fudd.com’ 更新的列名和新值
where
cust_id = 10005; 要更新新行的过滤数据。
update语句总是要以更新的表的名字开始。
update语句以where子句结束,告诉MySQL更新哪一行。如果没有where子句,那么将会根据这一个电子邮件地址更新这个表中的所有的行。
更新多个列:
update
customers
set
cust_name = ‘The Fudds’,cust_email = ‘elmer@fudd.com’ 更新这两个列
where
cust_id = 10005;
在update语句中使用子查询。和之前的子查询差不多。
ignore关键字:就是在更新多个行的时候,出现了一个错误,那怎么办呢?
即使发生错误,也继续进行更新,可使用ignore关键字
update ignore customers
为了删除某个列的值,可将这个列设置为null,
update customers set cust_email = null where cust_id = 10005;
20.2 删除数据
为了从一个表中删除数据,可使用delete语句。
两种方式:从表中删除特定的行,从表中删除所有的行。
不要省略where子句,同update
delete from customers where cust_id = 10006;
删除表的内容而不是表
更快的删除:如果想要从表中删除所有的行,不要使用delete,可使用truncate table语句。它比delete速度更快。
20.3 更新和删除的指导原则
注意点:除非确实打算更新和删除每一行,否则绝对不要使用delete和update。
保证每个表中都有主键,尽可能像where子句那样使用它。
在使用这两个之前,先使用select进行测试,保证过滤的是正确的记录。
使用强制实施引用完整性的数据库,这样MySQL将不允许删除具有与其他表相关联的数据的行。
小心使用这两个
6月14号——学习记录
1.MySQL——创建和操作表
21.1——创建表create table
一般有两种创建表的方法
使用具有交互式创建和管理工具
表也可以直接用MySQL语句操纵
21.1.1表创建基础
新表的名字,在关键字create table之后给出
表列的名字和定义,用逗号分隔
create table 表明
(
列名 数据类型 not null auto_increment,
…
primary key(主键列)
) engine=innodb;
21.1.2——使用null值(就是没有值或却值)
如果这个列是空值可以不写,反之如果这个列不是空值,那么必须写出这个列的值。
如果这个列不是空值,但是你插入值的时候插入的是空值,则会返回错误。
null值是默认的,如果不指定not null,那么就为null值。
注意:不要把null值和空字符串混淆;
null只是没有值,他不是空字符串。空字符串也是一个值。
21.1.3——主键再介绍
主键值必须是唯一的。表中的每个行必须具有唯一的主键值。
primary key(主键值1,主键值2)
多个主键值需要用逗号分隔开。
主键中只能使用不允许null值的列,允许为null值的列不能作为唯一标识。
21.1.4 ——使用auto_increment
告诉MySQL本列每当增加一行时自动增量。自动对该列增量,给该列赋予下一个可用的值。
每个表只有一个该列,而且它必须被索引(使它成为主键)
select last_insert_id():此语句返回最后一个auto_increment值。
21.1.5——指定默认值
比如举个例子(只列出一个列值说明):quantity int not null default 1,
在未给出数量的情况下使用数量1.
注意:不允许使用函数作为默认值,它只支持常量。
使用默认值而不是空值。
21.1.6——引擎类型
mysql有一个具体管理和处理数据的内部引擎。
如果你不写engine=innodb,则使用MySQL默认的myisam。
但是不是所用的语句都默认使用它。这就是为什么engine=语句非常重要的原因。
myisam和innodb的区别:
第一:innodb支持事务处理,不支持全文本搜索。
第二:myisam支持全文本搜索,不支持事务处理。
这两种使用分场景使用:
比如:你想让数据库表支持事务处理,就用第一个innodb
相反让数据库表支持全文本搜索就有第二个。
一般如果不需要可靠的事务处理就使用myisam就行了。
外键不能跨引擎。这也是一个缺陷。即使用一个引擎的表不能引用具有使用不同引擎的表的外键。
21.2——更新表alter table
数据少的时候可以稍微更新,但是数据量大的时候不建议更新表(因为浪费时间)。
增加一个列:
代码:alter table vendors add vend_phone char(20);
删除一个列:alter table vendors drop column vend_phone;
alter table的一种常见的用途是定义外键。
重点:
alter table orderitems
add constraint fk_orderitems_orders
foreign key (order_num)
references orders (order_num);
21.3——删除表drop table
drop table 要删除的表名;
21.4——重命名表
rename table语句
rename table customers2 to customers;重命名一个表。要是多个表要用逗号分隔。
rename table backup_customer to customers, backup_vendors to vendors;
21.5——小结
6月15号学习记录
第二十二章——使用视图
22.1——视图
视图是虚拟的表。与包含的数据不一样,视图只包含使用时动态检索数据的查询。
看一个例子:之前的例子
select cust_name, cust_contact
from customers, orders, orderitems
where customers.cust_id = orders.cust_id
and orders.order_num = orderitems.order_num
and prod_id = “TNT2”;
现在,假如可以把整个查询包装成一个名为productcustomers的虚拟表,则可以如下轻松地检索出相同的数据。
select cust_name, cust_contact
from productcustomers
where prod_id = “TNT2”;
这就是视图的作用。productcustomers是一个视图,作为视图,它不应该包含表中应该有的任何列或数据,它只包含的是一个SQL查询(与上面用以正确联结表的相同的查询)。
22.1.1 为什么使用视图
第一:重用SQL语句。
第二:简化复杂的SQL操作。
第三:使用表的组成部分而不是整个表。
第四:保护数据(可以给用户授予表的特定部分的访问权限而不是整个表的访问权限)。
第五:更改数据格式和表示。
在视图创建之后,可以用与表基本相同的方式利用它们。可以对视图进行select操作,过滤和排序数据,将视图联结到其他视图或表。甚至能添加和更新数据。
视图仅仅是用来查看存储在别处的数据的一种设施。视图本身不包含数据,因此它们返回的数据是从其他表中检索出来的。在添加或更改这些表中的数据时,试图将返回改变过的数据。
创建多个视图或者嵌套多个视图,性能会下降,所以在使用大量视图前,应该进行测试。
22.1.2——视图的规则和限制
第一:视图和表一样必须唯一命名。
第二:视图的创建数目没用限制。
第三:为了创建视图,必须具有足够的访问权限。
第四:视图可以嵌套。
第五:order by 可以用在视图中。
第六:视图不能索引
第七:视图可以和表一起使用。
22.2 使用视图
第一:视图用create view语句来创建。
第二:使用show create view viewname;来查看创建的视图的语句。
第三:用drop删除视图,其语法为drop view viewname;
第四:更新视图时,可以先用drop再用create,也可以直接用create or replace view。
如果更新的视图不存在,则第二条语句会创建一个视图,如果更新的语句存在,则第二条更新语句会替换原有视图。
22.2.1——利用视图简化复杂的联结
视图的最常用的应用之一是隐藏复杂的SQL,这通常会涉及联结。
create view productcustomers as 创建视图语句
select cust_name, cust_contact, prod_id
from customers, orders, orderitems
where customers.cust_id = orders.cust_id
and orders.order_num = orderitems.order_num;
利用创建好的视图检索数据
select cust_name, cust_contact
from productcustomers
where prod_id =“TNT2”;
通过where子句从视图中检索特定的语句。
本章重点掌握:可以看出来,视图极大地简化了复杂的SQL语句的使用。利用视图,可一次性编写基础的SQL,然后哦根据需要多次使用。——创建可重用的视图。
22.2.2 用视图重新格式化检索出的数据。
视图的另一种常见的用途是重新格式化检索出的数据。
create view vendorlocation as
select concat(vend_name, ‘(’,vend_country, ‘)’)
as vend_title
from vendors
order by vend_name;
select * from vendorlocation;
加入经常需要这个格式的结果,不必再每次需要时执行联结,创建一个视图每次需要它时使用它就行了。
22.2.3——用视图过滤不想要的数据。
视图对于应用普通的where子句也很有用。比如过滤没有电子邮箱的地址的客户。
create view customeremaillist as
select cust_id, cust_name, cust_email
from customers
where cust_email is not null;
where子句过滤了cust_email列中具有null值的那些行,使他们不被检索出来。
select * from customeremaillist;
22.2.4——使用视图与计算字段
视图对于简化字段的使用特别有用。
create view orderitemsexpand as
select order_num, prod_id, quantity, item_price,
quantity*item_price as expanded_price
from orderitems;
select * from
orderitemsexpand
where order_num = 20005;
总结:可以看到视图的创建非常容易,而且很好使用。正确使用,视图可极大地简化复杂的数据处理。
22.2.5——更新视图
现在为止所有的视图都是和select语句使用的。
通常视图是可更新的(即,可以对它们使用insert,update和delete)。
更新一个视图将更新其基表(视图本身是没有数据的),如果你对视图增加或删除行,实际上是对其基表增加或删除行。
但是并非所用的视图都是可更新的。
以下是不能进行视图的更新:
分组(使用group by和having),联结,子查询,并,聚集函数(Min()、Count()、Sum()等);distinct;导出(计算)列。
换句话说,其实大部分例子中都是不能进行视图更新的。这听上去好像是一个严重的限制,但实际上不是,因为视图主要用于数据检索(这才是视图的重点)。
一般应该将视图由于检索(select语句),而不用于更新(insert,update,delete)。
6月16号学习记录
第二十三章——使用存储过程
23.1——存储过程
存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。
可将其视为批文件,虽然他们的作用不仅限于批处理。
23.2 为什么要使用存储过程
理由:第一:简化复杂的操作;
第二:保证了数据的完整性;
第三:简化对变动的管理(安全性);
第四:提高性能——使用存储过程比使用单独地SQL语句要快。
总结:好处:简单、安全、高性能
缺陷:第一:存储过程的编写比基本SQL语句复杂,编写存储过程需要更高的技能,更丰富的经验。
第二:你可能没有创建存储过程的安全访问权限。可以使用但是不能创建。
23.3——使用存储过程
使用存储过程需要知道如何执行(运行)它们。
6月17号学习过程
23.3.1——执行存储过程
mysql称存储过程的执行为调用,因此MySQL执行存储过程的语句为call。
call接受存储过程的名字以及需要传递给它的任意参数。
代码例子:
call productpricing(@pricelow, @pricehight, @priceaverage);
其中名为productpricing的存储过程,计算并返回产品的最低、最高和平均价格。
23.3.2——创建存储过程
编写存储过程并不是微不足道的事情。
例子:一个返回产品平均价格的存储过程。
create procedure productpricing() #创建一个存储过程名为productpricing记住后面的括号不要忘了,如果存储过程接收参数,它们将在()中列举出来。此存储过程没有参数但是()仍然需要。
begin #开始
select avg(prod_price)
as priceaverage
from products;
end;#结束
这条语句没有返回的结果。
解释:存储过程名称为 ——productpricing
begin和end语句用来限定存储过程体,过程体本身仅是一个简单的select语句。使用了一个AVG()函数。
这条语句并未调用存储过程,所以没有返回的结果。只是为了以后使用而创建它。
下面是对——MySQL命令行客户机的分隔符
delimiter // 告诉命令行实用程序使用//作为新的语句结束分隔符。
create procedure productpricing()
begin
select avg(prod_price)
as priceaverage
from products;
end //
delimiter; 最后为了恢复原来的语句分隔符使用delimiter;
那么怎么使用刚才创建的存储过程名为productpricing呢?
call productpricing(); #执行刚才创建的存储过程并显示返回的结果。
因为存储过程实际上是一种函数,所以存储过程名后需要有()符号,即使不传递参数也需要。
23.3.3——删除存储过程
存储过程在创建之后,被保存在服务器上以供使用,直到被删除。
drop procedure productpricing; 注意存储过程后面没有()
23.3.4——使用参数
productpricing只是一个简单的存储过程,它简单地显示select语句的结果。一般,存储过程并不显示结果,而是把结果返回给你指定的变量。
变量:用来临时存储数据。
以下是productpricing的修改版本(如果不先删除此存储过程,则不能再次创建它);
create procedure productpricing
(out pl decimal(8,2),
out ph decimal(8,2),
out pa decimal(8,2))
begin
select min(prod_price) into pl from products;
select max(prod_price) into ph from products;
select avg(prod_price) into pa from products;
end;
解释代码:此存储过程接受3个参数,pl ph pa代表产品最低价格,最高价格,平均价格
每个参数必须具有指定的类型。
关键字out指出相应的参数用来从存储过程传出一个值(返回给调用者)。
mysql支持in(传递给存储过程),out(此存储过程传出),和inout(对存储过程传入和传出)类型的参数。
存储过程的代码位于begin和end语句内,它们是一系列select语句。用来检索值,然后保存到相应的变量(通过指定into关键字)。
存储过程的参数允许的数据类型与表中使用的数据类型相同。
由于存储过程中有三个变量,所以在调用时,必须指定三个参数。
call productpricing(
@pricelow,
@pricehight,
@priceaverage
);
call语句要给出三个参数,它们是存储过程将保存结果的三个变量的名字。
注意:所有MySQL变量都必须以@开始。
在调用时,这条语句并不显示任何数据。它返回以后可以显示(或在其他处理中使用)的变量。
想要显示数据则执行以下语句:
select @pricelow,@pricehight, @priceaverage;
再看一个例子——这次使用in和out参数。
ordertotal接受订单号并返回该订单的合计:
create procedure ordertotal
(in onumber int,
out ototal decimal(8,2))
begin
select sum(item_price*quantity) from orderitems
where order_num = onumber into ototal;
end;
call ordertotal(20005, @total);得到20005的订单合计
call ordertotal(20009, @total);得到20009的订单合计
select @total;
6月24号学习记录
23.3.5 ——建立智能存储过程(难点)
目前为止见到的所用的存储过程基本上都是封装的MySQL的简单select语句查询。
虽然他们都是有效的存储过程例子,但他们所能完成的工作你直接用这些被封装的语句就能完成。
(如果说它们还能带来更多的东西,那就是使事情更复杂。)
只有在存储过程内包含业务逻辑规则和智能处理时,它们的威力才真正显示出来。
例子:需求——需要获得与以前一样的订单合计,但是需要对合计增加营业税,不过只针对某些顾客(或许是你所在州中那些顾客)。那么,你需要做下面几件事情。
- 获得合计
2.把营业税有条件地添加到合计
3.返回合计(带或不带税)
代码实例:(前提是你要先删除之前的ordertotal)
– Name: ordertotal --代表注释在前面放置,后面就是注释的内容,
-> – Parameters: onumber = order number 在存储过程增加时,这样做特别重要。
-> – taxable = 0 if not taxable, 1 if taxable
-> – ototal = order total variable
-> create procedure ordertotal(
-> in onumber int,
-> in taxable boolean, 添加了另外一个参数他是一个布尔值(如果要增加税则为真,否则为假。)
-> out ototal decimal(8,2)
-> )
-> begin
-> – Declare variable for total 在存储过程体中,用declare语句定义了两个局部变量。declare要求指定变量名和数据类型。
-> declare total decimal(8,2);
-> – Declare tax percentage
-> declare taxrate int default 6;他也支持可选的默认值——taxrate的默认值被设置为6%
-> – Get the order total
-> select sum(item_pricequantity)
-> from orderitems
-> where order_num = onumber
-> into total; select语句以及改变,其结果存储到total局部变量而不是ototal
-> – Is this taxable?
-> if taxable then if语句检查taxable是否为真,如果为真,则用另一select语句增加营业税到局部变量total。
-> – Yes, so add taxable to the total
-> select total+(total/100taxrate) into total;
-> end if;
-> – And finally, save to out variable 最后,用另一select语句将total(它增加或许不增加营业税)保存到ototal。
-> select total into ototal;
-> end;
call ordertotal(20005,0, @total); 调用存储过程,这里是三个参数。
select @total; 查询存储过程的数据
call ordertotal(20005,1, @total);
select @total;
comment 关键字,不是必需的,但如果给出,将在 show procedure status的结果中显示。
总结:这显然是一个更高级,功能更强的存储过程。
这个例子中还给出了MySQL中的if语句的基本用法,if语句还支持elseif和else子句(前者还使用then子句,后者不使用)。
23.3.6——检查存储过程
为显示用来创建一个存储过程的create语句,使用show create procedure语句。
show create procedure ordertotal;
为了获得包括何时、由谁创建等详细信息的存储过程列表,使用
show procedure status 列出所有存储过程。
为限制其输出,可使用like制定一个过滤模式,例如:
show procedure status like ‘ordertotal’;
6月25号学习记录
第二十四章——使用游标
24.1——游标(cursor)
游标是一个存储在MySQL服务器上的数据库查询,它不是一条select语句,而是被该语句检索出来的结果集。
在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
有时,需要在检索出来的行中前进或后退一行或多行。这就是使用游标的原因。
游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或作出更改。
注意:MySQL游标只能用于存储过程(和函数)。
24.2 ——使用游标
使用游标涉及几个明确的步骤。
1.在能够使用游标前,必须声明(定义它)。
这个过程实际上没有检索数据,只是定义要使用的select语句。
2.一旦声明后,必须打开游标以供使用。
这个过程用前面定义的select语句把数据实际检索出来。
3.对于填有数据的游标,根据需要取出(检索)各行。
4.在结束游标使用时,必须关闭游标。
在声明游标后,可根据需要频繁地打开和关闭游标。
在游标打开后,可根据需要频繁地执行取操作。
24.2.1——创建游标
游标用declare语句创建。
declare命名游标,并定义相应的select语句。
根据需要带where和其他子句。
例子——下面的语句定义了名为ordernumbers的游标,
使用了可以检索所有订单的select语句。
create procedure processorders()
-> begin
-> declare ordernumbers cursor
-> for
-> select order_num from orders;
-> end;
解释一下:这个存储过程并没有做很多事情,declare语句用来定义和命名游标,这里为ordernumbers。存储过程处理完成后,游标就消失了(因为它局限于存储过程)。
24.2.2——打开和关闭游标
打开游标:open ordernumbers;
关闭游标:close ordernumbers;
close 释放游标使用的所有内部内存和资源,因此在每个游标不再需要时都应该关闭。
在一个游标关闭后,如果没有重新打开,则不能使用它。
但是,使用声明过的游标不需要再次声明,用open语句打开就可以了。
隐含关闭:如果你不明确关闭游标,MySQL将会在到达end语句时自动关闭它。
修改版本:
create procedure processorders()
-> begin
-> – Declare the cursor
-> declare ordernumbers cursor
-> for
-> select order_num from orders;
-> – Open the cursor
-> open ordernumbers;
-> – Close the cursor
-> close ordernumbers;
-> end;
这个存储过程声明、打开和关闭一个游标。
但对检索出的数据什么也没做。
24.2.3——使用游标数据
在一个游标被打开后,可以使用fetch语句分别访问它的每一行。
fetch指定检索什么数据(所需的列),检索出来的数据存储在什么地方。
他还向前移动游标中的内部行指针,使下一条fetch语句检索下一行(不重复读取同一行)。
代码如下:
create procedure processorders()
-> begin
-> – Declare local variables
-> declare done boolean default 0; (default 0假,不结束)定义变量done。
-> declare o int;
-> – Declare the cursor
-> declare ordernumbers cursor
-> for
-> select order_num from orders;
-> – Declare continue handler //continue handler,他是在条件出现时被执行的代码。这里,他指出当sqlstate ‘02000’ 出现时,set done=1. sqlstate '02000’是一个未找到的条件,当repeat由于没有更多的行供循环而不能继续时,出现这个条件。
-> declare continue handler for sqlstate ‘02000’ set done=1; 结束时被设置为真done=1
-> – open the cursor
-> open ordernumbers;
-> – loop throgh all rows
-> repeat
-> – get order number
-> fetch ordernumbers into o; 使用fetch检索当前order_num到变量o中。但是这个fetch是在repeat内,因此它反复执行直到done为真。( until done end repeat;)
-> – end of loop
-> until done end repeat;
-> – Close the cursor
-> close ordernumbers;
-> end;
注意:declare定义的次序:
declare定义局部变量必须在任意游标或句柄之前定义。
句柄必须在游标之后定义。
如果调用这个存储过程,它将定义几个变量和一个continue handler, 定义并打开一个游标,重复读取所有的行,然后关闭游标。
通常repeat语句的语法使它更适合于对游标进行循环。
7月1号学习进度
为了把这些内容组织起来,下面给出我们的游标存储过程样例的更进一步修改,这次对取出的数据进行某种实际的操作:
create procedure processorders()
begin
– Declare local variable
declare done boolean default 0;
declare o int;
declare t decimal(8,2); //我们增加了另一个名为t的变量(存储每个订单的合计)
– Declare the cursor
declare ordernumbers cursor
for
select order_num from orders;
– Declare continue handler
declare continue handler for sqlstate ‘02000’ set done=1;
– Create a table to store the results
create table if not exists ordertotals //首先这个ordertotals这个新表你要先创建好。这个表将保存存储过程生成的结果。
(order_num int, total decimal(8,2));
– Open the cursor
open ordernumbers;
– Loop through all rows
repeat
– Get order number
fetch ordernumbers into o; //fetch像以前一样取每个order_num,然后用call执行另一个存储过程来计算每个订单的带税的合计(结果存储到t)。
– Get the total for this order
call ordertotal(o, 1, t);
– Insert order and total into ordertotals
insert into ordertotals(order_num, total) //最后,用insert保存每个订单的订单号和合计。
values(o, t);
– End of loop
until done end repeat;
– Close the cursor
close ordernumbers;
end;
此存储过程不返回数据,但它能够创建和填充另一个表,用一条简单的select语句查看该表。
select * from ordertotals;
这样我们就得到了存储过程、游标、逐行处理以及存储过程调用
其他存储过程的一个完整的工作样例。
第二十五章——触发器
25.1——触发器
如果你想要某条语句(或某些语句)在事件发生时自动执行,怎么办呢?
例如:
每当增加一个顾客到某个数据库表时,都检查其电话号码格式是否正确,州的缩写是否为大写。
每当订购一个产品时,都从库存数量中减去订购的数量。
无论何时删除一行,都在某个存档表中保留一个副本。
这些例子的共同之处是它们都需要在某个表发生更改时自动处理——这确切地说就是触发器。
触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句。(或位于begin和end语句之间的一组语句):
delete
insert
update
其它MySQL语句不支持触发器。
25.2——创建触发器
在创建触发器时,需要给出4条信息:
1.唯一的触发器名;
2.触发器关联的表;
3.触发器应该响应的活动(delete、insert或update);
4.触发器何时执行(处理之前或之后)。
注意:保持每个数据库的触发器名唯一。
触发器用 create trigger语句创建。
学习MySQL出现问题Not allowed to return a result set from a trigger
情况描述:
按书本代码输入
CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROW SELECT ‘Product added’//
出现错误Not allowed to return a result set from a trigger
查找原因是:MYSQL5以后,不允许触发器返回任何结果,因此使用into @变量名,将结果赋值到变量中,用select调用即可
修改为
CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROW SELECT ‘Product added’ INTO @asd// # 变量名用@引导 # DELIMITER // 将语句结束符号;修改为//
成功!
看看变量里有啥?
SELECT @asd//
啥也没,还没插入操作,所以显示没有值!
在products表插入一行数据: 友情提示,插入数据时注意每列的数据类型,且保证主键列的数据不重复
再运行SELECT @asd//
现在有了!
create trigger——用来创建名为newproduct的新触发器。
after insert——触发器可在一个操作发生之前或或之后执行。
所以此触发器将在insert语句成功执行后执行。
这个触发器还指定for each row,因此代码对每个插入行执行。
在这个例子中,文本Product added将对每个插入的行显示一次。
为了测试这个触发器,使用insert语句添加一行或多行到products中,你将看到对每个成功的插入,显示Product added消息。
注意:触发器仅支持表。只有表才支持触发器,视图不支持(临时表也不支持)。
触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。
因此,每个表最多支持6个触发器(每条insert、update和delete的之前和之后)。
单一触发器不能与多个事件或多个表关联,所以,如果你需要一个对insert和update操作执行的触发器,则应该定义两个触发器。
注意:触发器失败——如果before触发器失败,则MySQL将不执行请求的操作。
此外,如果before触发器或语句本身失败,MySQL将不执行after触发器(如果有的话)。
25.3——删除触发器
drop trigger newproduct;
触发器不能更新或覆盖,为了修改一个触发器,必须先删除它,然后再重新创建。
25.4——使用触发器
所支持的每种触发器类型以及它们的差别。
7月2号——学习记录
25.4.1——insert触发器
insert触发器在insert语句执行之前或之后执行。
需要知道以下几点:
1.在insert触发器代码内,可引用一个名为new的虚拟表,访问被插入的行。
2.在before insert触发器中,new中的值也可以被更新(允许更改被插入的值)。
3.对于auto_increment列,new在insert执行之前包含0,在insert执行之后包含新的自动生成值。
例子:
auto_increment列具有MySQL自动赋予的值。
create trigger neworder after insert on orders
-> for each row select new.order_num into @on;
代码说明:此代码创建一个名为neworder的触发器。
按照after insert on orders执行。
在插入一个新订单到orders表时,MySQL生成一个新订单号并保存到order_num中。
触发器从new.order_num取得这个值并返回它。
此触发器必须按照after insert执行,因为在before insert语句执行之前,
新的order_num还没有生成。
对于orders的每次插入使用这个触发器将总是返回新的订单号。
为了测试这个触发器,试着插入一下新行,
insert into orders(order_date, cust_id)
-> values(now(), 10001);
select * from orders;
±----------±--------------------±--------+
| order_num | order_date | cust_id |
±----------±--------------------±--------+
| 20010 | 2022-07-02 14:48:02 | 10001 |
±----------±--------------------±--------+
orders包含3个列。order_date和cust_id必须给出,
order_num由MySQL自动生成,而现在order_num还自动被返回。
注意:before或after,通常,将before用于数据验证和净化(目的是保证插入表中的数据确实是需要的数据)。也适用于update触发器。
25.4.2——delete触发器
delete触发器在delete语句执行之前或之后执行。
需要知道以下两点:
1.在delete触发器代码内,你可以引用一个名为old的虚拟表,访问被删除的行。
2.old中的值全都是只读的,不能更新。
例子:演示使用old保存将要被删除的行到一个存档表中:
create trigger deleteorder before delete on orders
-> for each row
-> begin
-> insert into archive_orders(order_num, order_date, cust_id)
-> values(old.order_num, old.order_date, old.cust_id);
-> end;
在任意订单被删除前将执行此触发器。它使用一条insert语句将old中的值(要被删除的订单)保存到一个名为archive_orders的存档表中(为实际使用这个例子,你需要用与orders相同的列创建一个名为archive_orders的表)。
使用before delete触发器的优点(相对于after delete触发器来说)为:如果由于某种原因,订单不能存档,delete本身将被放弃。
多语句触发器:触发器deleteorder使用begin和end语句标记触发器体。
使用begin end块的好处是触发器能容纳多条SQL语句。(在begin end块中一条挨着一条)。
25.4.3——update触发器
update触发器在update语句执行之前或之后执行。
需要知道以下几点:
1.在update触发器代码中,你可以引用一个名为old的虚拟表访问以前(update语句前)的值,引用一个名为new的虚拟表访问新更新的值。
- 在before update触发器中,new中的值可能也被更新(允许更改将要用于update语句中的值);
3.old中的值全都是只读的,不能更新。
例子:保证州名缩写总是大写(不管update语句中给出的是大写还是小写):
create trigger updatevendor before update on vendors
-> for each row set new.vend_state = upper(new.vend_state);
任何数据净化都需要在update语句之前进行,就像这个例子一样。每次更新一个行时,
new.vend_state中的值(将用来更新表行的值)都用upper(new.vend_state)替换。
25.4.4——关于触发器的进一步介绍
再介绍一些使用触发器时需要记住的重点。
1.创建触发器可能需要特殊的安全访问权限,但是触发器的执行是自动的。如果insert、delete、update语句能够执行,则相关的触发器也能执行。
2.应该用触发器来保证数据的一致性(大小写、格式等)。
3.触发器的一种非常有意义的使用是创建审计跟踪。
使用触发器把更改记录到另一个表非常容易。
4.遗憾的是,MySQL触发器不支持call语句。
这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。
7月3号学习记录
第二十六章——管理事务处理
什么是事务处理?以及如何利用commit和rollback语句来管理事务处理
26.1——事务处理
并非所有引擎都支持事务处理。
MySQL中最常用的数据引擎是——MyISAM 和innodb。
前者不支持明确的事务处理,而后者支持。
这就是为什么本书中使用的样例表被创建来使用innodb而不是更经常使用的MyISAM的原因。
如果你的应用中需要事务处理功能,则一定要使用正确的引擎类型。
事务处理(transaction processing):可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行。
7月4号——学习记录
例子:给系统添加订单的过程。
1.检查数据库中是否存在响应的客户(从customers表查询),如果不存在,添加客户。
2.检索客户的ID。
3.添加一行到orders表,把它与客户ID关联。
4.检索orders表中赋予的新订单ID。
5.对于订购的的每个物品在orderitems表中添加一行,通过检索出来的ID把它与orders表关联(以及通过产品ID与product表关联)。
假如现在由于某种数据库故障阻止了这个过程的完成。数据库中的数据会出现什么情况?
如果故障发生在添加客户之后,orders表添加之前,不会有什么问题。
某些客户没有订单是完全OK的。再重新执行此过程,所插入的客户记录将被检索和使用。
可以有效地从出故障的地方开始执行此过程。
但是,如果故障发生在orders行添加之后,orderitems行添加之前,怎么办?
数据库中有个一个空订单。如果系统在添加orderitems行之中出现故障。结果是数据库中存在不完整的订单,而且你还不知道。
这个问题就需要事务处理来解决了。
事务处理是一种机制,用来管理必须成批执行的MySQL操作,以保证数据库不包含不完整的操作结果。
利用事务处理,可以保证一组操作不会中途停止,它们或者作为整体执行,或者完全不执行。
如果没有错误发生,整组语句提交给(写到)数据库表。
如果发生错误,则进行回退,已恢复数据库到某个已知且安全的状态。
例子:
1.检查数据库中是否存在响应的客户,如果不存在,添加客户。
2.提交客户的信息。
3.检索客户的ID。
4.添加一行到orders表。
5.如果在添加行到orders表时出现故障,回退。
6.检索orders表中赋予的新订单ID。
7.对于订购的每项物品,添加新行到orderitems表。
8.如果在添加新行到orderitems时出现故障,回退所有的添加的orderitems行和orders行。
9.提交订单信息。
有关事务的几个术语:
事务(transaction):指一组SQL语句。
回退(rollback):指撤销指定SQL语句的过程。
提交(commit):指将未存储的SQL语句结果写入数据库表。
保留点(savepoint):指事务处理中设置的临时占位符,你可以对它发布回退(与回退整个事务处理不同)。
26.2——控制事务处理
管理事务处理的关键在于将SQL语句分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
MySQL使用下面的语句来标识事务的开始:
start transaction;
26.2.1——使用rollback
MySQL的rollback命令用来回退(撤销)MySQL语句,
例子:
select * from ordertotals;//首先执行一条select以显示该表不为空。
start transaction; //然后开始一个事务处理
delete from ordertotals;//用一条delete语句删除表中的所有行
select * from ordertotals;//另一条select语句验证表确实为空
rollback;//这时用一条rollback语句回退start transaction之后的所有语句。
select * from ordertotals; //最后一条select语句显示该表不为空
显然,rollback只能在一个事务处理内使用(在执行一条select transaction命令之后)。
哪些语句可以回退:
事务处理用来管理insert、update、delete语句。
其他的语句就不用管了。
26.2.2——使用commit
一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交,
即提交(写或保存)操作是自动进行的。
但是在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用commit语句。
在这个例子中,从系统中完全删除订单20010.
涉及到两个表,所以使用事务处理块来保证订单不被部分删除。
如果第一条delete起作用,但第二条失败,则delete不会提交(实际上,它是被自动撤销的)。
注意:当commit或rollback语句执行后,事务会自动关闭(将来的更改会隐含提交)。
26.2.3——使用保留点
简单的rollback和commit语句就可以写入或撤销整个事务处理。
但是,只是对简单的事务处理才能这样做,更复杂的事务处理可能需要部分提交或回退。
例如前面描述的添加订单的过程为一个事务处理。
如果发生错误,只需要返回到添加orders行之前即可,不需要回退到customers表(如果存在的话)。
为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。
这样,如果需要回退,可以回退到某个占位符。
这些占位符称为保留点。为了创占位符,可如下使用
savepoint delete1;
上面的错误解决方法:
您必须使用 start transaction; 而不是 begin 来启动存储过程中的事务。
此外,您可能需要将 savepoint 语句移到 declare之后(取决于您放置 start transaction 的位置)
rollback to point1;——回退到保留点
注意:保留点越多越好:可以在MySQL代码只设置任意多的保留点,越多越好。
保留点越多,你就越能按自己的意愿进行回退。
释放保留点:保留点在事务处理完成(执行一条rollback或commit)后自动释放。
26.2.4——更改默认的提交行为
任何时候你执行一条MySQL语句,该语句实际上都是针对表执行的,而且所做的的更改立即生效。
为指示MySQL不自动提交更改,需要使用以下语句:
set autocommit = 0;
autocommit 标志决定是否自动提交更改,不管有没有commit语句。设置autocommit = 0(假)指示MySQL不自动提交更改(直到autocommit被设置为真为止)。
autocommit标志是针对每个连接而不是服务器的。
7月6号——学习记录
第二十七章——全球化和本地化
MySQL处理不同字符集和语言的基础知识
27.1——字符集和校对顺序
数据库表被用来存储和检索数据。不同的语言和字符集需要以不同的方式存储和检索。
MySQL需要适应不同的字符集,适应不同的排序和检索数据的方法。
术语:
字符集:字母和符号的集合。
编码:某个字符集成员的内部表示。
校对:规定字符如何比较的指令。
27.2——使用字符集和校对顺序
MySQL支持众多的字符集。为查看所支持的字符集完整列表,使用以下语句:(图片我只截取了一部分作为参考)
show character set;
这条语句显示所有可用的字符集以及每个字符集的描述和默认校对。
为了查看所支持的校对的完整列表,使用以下语句:(图片我只截取了一部分作为参考)
show collation;
这条语句显示所有可用的校对,以及它们适用的字符集。可以看到有的字符集具有不止一种校对。
例如:latin1对不同的语言有几种校对,而且许多校对出现两次,一次区分大小写(由_cs表示),一次不区分大小写(由_ci表示)。
通常系统管理在安装时定义一个默认的字符集和校对。此外,也可 以在创建数据库时,指定默认的字符集和校对。为了确定所用的字符集 和校对,可以使用以下语句:
show variables like ‘character%’;
show variables like ‘collation%’;
为了给表指定字符集和校对,可使用带子句的create table:
代码:
create table mytable
-> (
-> columnn1 int,
-> columnn2 varchar(10)
-> ) default character set hebrew
-> collate hebrew_general_ci
-> engine=innodb;
此语句创建一个包含两列的表,并且指定一个字符集和一个校 对顺序。
这个例子中指定了character set和collate两者。
一般,MySQL如下确定使用什么样的字符集和校对。
1.如果指定character set和collate两者,则使用这些值。
2.如果只指定character set,则使用此字符集及其默认的校对(如show character set的结果中所示)。
3.如果既不指定character set,也不指定collate,则使用数据库默认。
create table mytable
-> (
-> columnn1 int,
-> columnn2 varchar(10),
-> columnn3 varchar(10) character set latin1 collate
-> latin1_general_ci
-> ) default character set hebrew
-> collate hebrew_general_ci;
这里对整个表以及一个特定的列指定了character set和 collate。
select * from customers
-> order by lastname, firstname
-> collate latin1_general_cs;
此select使用collate指定一个备用的校对顺序(在这个例子 中,为区分大小写的校对)。这显然将会影响到结果排序的次序。
注意:
1.临时区分大小写 :上面的select语句演示了在通常不区分大 小写的表上进行区分大小写搜索的一种技术。当然,反过来 也是可以的。
2.select的其他collate子句 除了这里看到的在order by子句中使用以外,collate还可以用于group by、having、聚集函数、别名等。
3.字符串可以在字符集之间进行转换,使用Convert()函数(了解)
最后
以上就是平淡板凳为你收集整理的个人博客学习记录的全部内容,希望文章能够帮你解决个人博客学习记录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复