EXISTS() 函数:
判断函数体内的Sql语句是否存在/正确。是,则返回true,否,则返回false
解读:每对products表中的一条记录进行查询时,都会执行EXISTS函数,从order_items表中遍历,查找order_items表中是否有记录的product_id与product相匹配,如果有,则返回true。这个函数并不会返回一个集合给外查询,因此在非常复杂的数据中,可以非常好的提升查询效率。
SELECT子句中的子查询:
如果不想当复读机,则可以使用 SELECT(子句中通过子查询获得的列名称)
FROM子句中的子查询:
通过SELECT获取的表,添加别名后,可以用于FROM子句中的子查询(仅限于简单的查询)。但是会让主查询变得更复杂。
MySQL内置函数:
ROUND(x, y) -- 轮函数,用来四舍五入数字 x,将要四舍五入的数字,y保留了几位小数
TRUNCATE(x, y) -- 截断函数,x:被截断的数字,y:截断几位小数
CEILING(x) -- 返回最小的大于或等于该数的最大整数
FLOOR(x) -- 获得小于或等于该数的最大整数
ABS(x) -- 获取x的绝对值
RAND() -- 生成0-1区间的随机浮点数
处理字符串值的函数:
LENGTH(x) -- 获取x字符串的长度
注意:使用UTF-8的汉字,每一个占3各字节,即 SELECT LENGTH('在这里') --- 9
UPPER(x) -- 小写转大写
LOWER(x) -- 大写转小写
LTRIM('x') -- 删除x字符串左边的空格
RTRIM('x') -- 删除x字符串右边的空格
TRIM('x') -- 删除x字符串所有前导或尾随空格
LEFT('x', y) -- 获取x字符串左边y个字符
RIGHT('x', y) -- 获取x字符串右边y个字符
SUBSTRING('x', startNum, totalNum) -- 从startNum个开始,获取x字符串中totalNum个字符,totalNum不写时,会获取到末尾
LOCATE('x', 'y') -- 获取x字符串在y字符串中第一次出现的位置,忽略大小写。没找到则返回0
REPLACE('wouldBeReplacedStr', 'fromStr', 'toStr') -- 参数一:将要被替换的总字符串 参数二:要被替换的字符串 参数三:替换的字符串
CONCAT(str1, str2) -- 合并两个字符串
MySQL日期函数:
NOW() -- 获取当前日期 + 时间
CURRENT_DATE() -- 获取当前日期
CURRENT_TIME() -- 获取当前时间
YEAR(x) -- 获取x日期中的年份
DAYNAME(x) -- 获取x日期对应的星期
MONTHNAME(x) -- 获取x日期对应的月份
EXTRACT(x)
日期格式化:
DATE_FORMAT(x, y) -- x:要格式化的日期,y='%y'获取2位的年份(2023得到23);y='%Y'获取具体的年份
y='%m'获取2位数的月份;y='%M'获取月份对应的英文
TIME_FORMAT(x, y) -- ....
计算时间和日期:
DATE_ADD(x, INTERVAL 1 DAY) -- x + 1天
DATE_SUB(x, INTERVAL 1 DAY) -- x - 1天DATEDIFF(x, y) -- 返回日期y距离x的天数
TIME_TO_SEC(x) -- 获取从午夜开始距离x的秒数
IFNULL()和COALESCE():
IFNULL(x, y) -- 如果x是null,则返回y
COALESCE(x, y, z..) -- 返回第一个非null的值
CASE函数:
CASEWHEN SUM(oi.quantity * oi.unit_price) > 3000 THEN 'gold' -- 条件WHEN SUM(oi.quantity * oi.unit_price) >= 2000 THEN 'silver'ELSE 'bronze' -- 前面都不符合,最终选项
END AS '列别名'CASE hero_name
WHEN '盖伦' THEN '上单'
WHEN '拉克丝' THEN '中单'
WHEN '金克斯' THEN 'ADC'
WHEN '琴女' THEN '辅助'
WHEN '盲僧' THEN '打野'
ELSE '混子' END
创建视图:
CREATE OR REPLACE VIEW 'view_name' AS (...
)
注意:如果AS内的函数没有用到DISTINCT关键字、任何聚合函数或者GROUP BY,也没有用到UNION运算符,就是一个可更新视图,可以修改数据。
如果更新或者删除可更新视图,原先行消失的话,可在CREATE语句末尾增加 WITH CHECK OPTION。
视图的好处(了解第1项即可):
CREATE PROCEDURE get_clients()
BEGINSELECT * FROM clients; -- 可以有多个SQL语句,但必须用';'结尾,MySQL规定
END
想把所有上述语句打包为一体给MySQL,而不是一个个用分号分离的语句,必须把 ';' 这个默认分隔符从分号改成别的什么:
DELIMITER $$ -- 修改默认分隔符($$是国际通用的,可以换成任何没有在SQL代码中用到的字符序列)
CREATE PROCEDURE get_clients()
BEGINSELECT * FROM clients;
END$$
-- 告诉MySQL,'$$'这是新的分隔符,把上述语句当作一个整体
DELIMITER ;
为什么要修改默认分隔符?
存储过程里的每一条语句都要用分号终止,修改分隔符,一切都是为了得以在存储过程中使用这个分号(有的不需要修改)
CALL get_clients() -- 调用存储过程
DROP PROCEDURE get_clients
DELIMITER $$
CREATE PROCEDURE get_client_by_state(state CHAR(2))
BEGINSELECT * FROM clients c WHERE c.state = state;
END $$
DELIMITER ;
IF ...SIGNAL SQLSTATE '错误码'SET MESSAGE_TEXT = '具体错误消息';
END IF;
CREATE PROCEDURE get_invoice(client_id INT, OUT invoices_total INT)
BEGINSELECTCOUNT(*)INTO invoices_totalFROM invoices iWHERE i.client_id = client_id;
END
-- 用户/会话变量(这些变量在整个客户会话过程中被保存,客户从MySQL短线后,这些变量消失)
SET @invoices_count = 0-- 本地变量(在存储过程或者函数内定义,函数/存储过程结束,变量即消失)
CREATE PROCEDURE get_risk_factor ()
BEGINDECLARE risk_factor DECIMAL(9, 2) DEFAULT 0;DECLARE invoices_total DECIMAL(9, 2); -- 声明本地变量DECLARE invoices_count INT;SELECT COUNT(*), SUM(invoice_total)INTO invoices_count, invoices_total -- 为本地变量赋值FROM invoices;SET risk_factor = invoices_total / invoices_count * 5;SELECT risk_factor;
END
和存储过程的区别:函数只能返回单一值,无法返回拥有多行和多列的结果集。
CREATE FUNCTION get_risk_factor_for_client
(client_id INT
)
RETURNS INTEGER
-- RETURN语句,这是函数和存储过程的主要区别,它明确了这个函数返回的值的类型
READS SQL DATA
-- RETURNS INTEGER:在RETURN函数之后,紧跟着要设置函数属性(可以有多个),每个MySQL都至少要有一个属性DETERMINISTIC -- 如果我们给予这个函数同样的一组值,它永远会返回一样的值(这在不想根据数据库中的数据返回值的时候很有用)
BEGINDECLARE risk_factor DECIMAL(9, 2) DEFAULT 0;DECLARE invoices_total DECIMAL(9, 2); -- 本地变量DECLARE invoices_count INT;SELECT COUNT(*), SUM(invoice_total)INTO invoices_count, invoices_totalFROM invoices iWHERE i.client_id = client_id;SET risk_factor = invoices_total / invoices_count * 5;RETURN IFNULL(risk_factor, 0); -- 返回结果
END-- 调用函数
SELECTclient_id,name,get_risk_factor_for_client(client_id)
FROM clients-- 删除函数
DROP FUNCTION IS EXISTS get_risk_factor_for_client
触发器是在插入、更新和删除语句前后自动执行的一堆SQL代码。通常使用触发器增强数据的一致性。
DELIMITER $$-- 这个触发器中我们可以修改任何表中的数据,除了这个触发器所在表(payments),否则就会变成无限轮回
CREATE TRIGGER payments_after_insertAFTER INSERT ON payments -- 标识触发器在什么时候触发FOR EACH ROW -- 意思是这个触发器会作用于每一个受影响的行
BEGINUPDATE invoicesSET payment_total = payment_total + NEW.amount -- NEW:返回刚刚插入的行WHERE invoice_id = NEW.invoice_id;
END $$DELIMITER ;
SHOW TRIGGERS; -- 查看触发器
DROP TRIGGER IF EXISTS trigger_name; -- 删除触发器
事件是根据计划执行的任务或一堆SQL代码。
SHOW VARIABLES LIKE 'event%'; -- 查看事件调度器(这是一个不停地寻找需要执行的事件的后台程序)SET GLOBAL event_scheduler = OFF;DELIMITER $$CREATE EVENT yearly_delete_stale_audit_rows
ON SCHEDULE-- AT '2023-10-15' 具体执行事件EVERY 1 HOUR -- 每1小时STARTS '2023-10-15' -- 开始时间(可选)ENDS '2033-10-15' -- 结束时间(可选)
DO BEGINDELETE FROM payment_auditWHERE action_date < DATE_ADD(NOW(), INTERVAL -1 YEAR);
END $$DELIMITER ;
SHOW EVENTS; -- 显示所有事件
DROP EVENT IF EXISTS event_name; -- 删除事件
ALTER EVENT event_name DISABLE; -- 禁用事件
ALTER EVENT event_name ENABLE; -- 启用事件
事务是代表单个工作单元的一组SQL语句。(要么同时成功,要么同时失败)
START TRANSACTION; -- 开启事务INSERT INTO orders (customer_id, order_date, status)
VALUES (1, '2023-10-15', 1);INSERT INTO order_items
VALUES (LAST_INSERT_ID(), 1, 1, 1)COMMIT; -- 提交事务
实际上在不主动声明启动事务的情况下,MySQL会先把它们装在事务里,然后自动提交,它由一个叫做自动提交的系统管控。
开启一个事务,并且随意修改一个数据。
开启另一个事务,并且修改相同行。发现一直等待。
提交第一个事务,第二个事务才执行成功。
开启事务时,MySQL放了一个所到我们更新的顾客行上,当另一个事务要改动这行时,会一直等待,直到持有锁的事务释放锁,才能执行。
MySQL有四大隔离级别:
读未提交(read uncommitted)
读已提交(read committed)
可重复读(repeatable read)
序列化读(serialized read)
MySQL默认隔离级别是repeatable read。
SELECT @@GLOBAL.TRANSACTION_ISOLATION; -- 查询当前隔离级别
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置隔离级别(为下一个事务设置)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置全局隔离级别(为当前会话设置)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置会话或者连接的隔离级别
脏读问题:即一个事务还没提交,另一个事务就可以读到该事务修改后的数据。
不可重复读问题:当读取了某个数据两次,并得到了不同的结果。
幻读:当查询中缺失了一行或者多行,因为有另一个事务正在修改数据,而我们没有意识到事务的修改。
读未提交:读取到为提交事务的数据。存在脏读问题。即一个事务还没提交,另一个事务就可以读到该事务修改后的数据
读已提交:读取到已提交事务的数据。存在不可重复读问题。当读取了某个数据两次,并得到了不同的结果
可重复读:一个事务中,数据不会因其它事务发生改变。存在幻读问题。当其它事务更新了数据并提交时,原事务不能及时读到修改后的数据。
序列化读 / 串行化读:事务是一个接着一个执行的。最高级别的隔离,解决了所有并发问题。
死锁:当不同事务均握住了别的事务需要的 “锁” 而无法完成的情况。所以两个事务都一直在等待对方,并永远没法释放锁。
-- 查询一:
START TRANSACTION;
UPDATE orders SET status = 2 WHERE order_id = 1;
UPDATE orders SET status = 1 WHERE order_id = 2;
COMMIT;-- 查询二:
START TRANSACTION;
UPDATE orders SET status = 1 WHERE order_id = 2;
UPDATE orders SET status = 2 WHERE order_id = 1;
COMMIT;
如何尽量避免死锁:
col_name DECIMAL(x, y) -- DECIMAL 表示小数,第一个参数代表位数,第二个参数达标小数点后的位数
CHAR(x) -- 存储固定长度字符串
VARCHAR(x) -- 存储可变长字符串(如用户名、密码、电子邮箱、地址等)-- 推荐
VARCHAR(50) -- 对短的可变长字符串
VARCHAR(255) -- 对中长类的可变长字符串
-- VARCHAR 最大可存储65535个字节(~64KB),可引入索引
MEDIUMTEXT -- max:16MB
LONGTEXT -- max:4GBTINYTEXT -- max:255bytes
TEXT -- max:64KB-- 注意:英文字母占用1个字节,欧洲和中东语言占用2个字节,亚洲语言占用3个字节
-- 所以如果列类型是CHAR(10),MySQL会为那列的值留出30字节
-- 用整数来存储1234这样没有小数点的整数TINYINT -- 1B [-128, 127]
UNSIGNED TINYINT -- [0, 255] 无符号数,防止负数被存入SMALLINT -- 2B [-32K, 32K]MEDIUMINT -- 3B [-8M, 8M]INT -- 4B [-2B, 2B]BIGINT -- 8B [-9Z, 9Z]
补0属性:INT(4) => 0001 这只会影响MySQL显示这些值的方式,而不是存储
在满足需求的情况下,最好使用最小的数据类型存储,这样你的数据库大小会更小,查询也会执行得更快。
DECIMAL(p, s) -- p:加上小数的总位数,s:小数的位数 DECIMAL(9, 2) => 1234567.89
DEC
NUMERIC
FIXED
-- 上述三个与第一个一样FLOAT -- 浮点类型 4B
DOUBLE -- 双精度类型 8B
-- 浮点型和双精度型不是存储精确的数据,而是近似值
BOOL
BOOLEAN
--------------------------------
UPDATE posts
SET is_published = TRUE / 1 # or FALSE / 0 -- '真'关键字其实本质可以用1表示,'假'可以用0表示
目录
存储过程
创建一个存储过程
使用MySQL工作台创建存储过程
删除存储过程
在存储过程中添加参数
参数验证
输出参数
变量
函数
触发器
事件
事务
并发和锁定
MySQL隔离级别
死锁
编辑
MySQL数据类型
STRINGS
INTEGERS
Fixed-point and Floating-point Types
Boolean Types
Enum and Set Types
Date and Time Types
Blob Types
JSON Type
设计数据库
-- 类似于Java的枚举类
ENUM('small', 'medium', 'large')
SET(...)
枚举类型的字段只能使用枚举中的值,否则报错:
尽量避免使用枚举类,改变枚举的组成项会很费功夫。
DATE -- 存储一个没有时间成分的日期
TIME --存储一个时间值DATETIME -- 8B
TIMESTAMP -- 4B(up to 2038) “存在2028问题”
YEAR
-- 以上三个存储四位数年份
使用Blob(二进制长对象)类型来存储大型二进制数据。如图像、视频、PDF、word文件。
TINYBLOB -- 255B
BLOB -- 65KB
MEDIUMBLOB -- 16MB
LONGBLOB -- 4GB
一般来说最好不要把文件存在数据库中,因为关系型数据库是为了处理结构化关系型数据设计的,而不是二进制数据。
{'KEY': VALUE
}-- 添加json数据
UPDATE products
SET properties = '
{"dimensions": [1, 2, 3],"weight": 10,"manufacturer": {"name": "sony"}
}
'
WHERE product_id = 1;-- 下列代码与上述一致
UPDATE products
SET properties = JSON_OBJECT('weight', 10,'dimensions', JSON_ARRAY(1, 2, 3),'manufacturer', JSON_OBJECT('name', 'sony')
)
WHERE product_id = 1;
-- 可以从JSON对象中提取单独的键值对
JSON_EXTRACT(JSON对象, 路径) -- 路径:$ 表示当前JSON文档
-- 假设属性列里想提取的只有“重量”
SELECT product_id, JSON_EXTRACT(properties, "$.weight")
FROM products
WHERE product_id = 1;-- 使用“列路径运算符” '->'
SELECT product_id, properties -> '$.weight'
FROM products
WHERE product_id = 1;-- 获取数组中具体的值
SELECT product_id, properties -> '$.dimensions[下标]'
FROM products
WHERE product_id = 1;-- 获取嵌套对象中的属性,获取属性带有大括号的话,将 -> 改为 ->>
SELECT product_id, properties -> '$.manufacturer.属性值'
FROM products
WHERE product_id = 1;
->:
->>:
-- 使用JSON_SET()函数修改json
UPDATE products
SET properties = JSON_SET(properties, -- JSON对象'$.age', 10
)
WHERE product_id = 1;-- 使用JSON_REMOVE()函数删除json中的属性
UPDATE products
SET properties = JSON_REMOVE(properties, -- JSON对象'$.age' -- 要删除的json的key
)
学习使用draw.io
下载:# 《draw.io压缩包》使用Entity模块创建对象实体。
多对多关系
创建类似上述的UML,意思是学生注册课程,这就是一个概念模型,它能让我们对业务领域和领域涉及内容有一个高度概览。至此还没有对每个属性类型的细节做出说明,我们既不知道也不关心未来会使用什么数据库管理系统来完成这个模型。现在仅仅是一个概念模型。我们用它来和商业参与方交接,所以我们能处于一个层次,也能让对方理解自己的表达内容,这就是概念模型的好处。
关系线:
添加一个字段,每个学生注册课程的日期:
不适合放到Student表中,因为一个Student可能有多个Course
也不适合放到Course表中,因为一个Course也可能包含多个Student,即每个学生的注册日期都不一样,所以注册日期不能算是课程的一种属性,而是注册的一种属性。
因此需要新建一个属性Entity。
创建逻辑模型:
构建Student和Enrollment之间的关系:一个Student对应多个Enrollment(一个学生可能会注册多个课程,每个注册的时间都可能不一样)
构建Course和Enrollment之间的关系:一个Course对应多个Enrollment(一个课程可能会被多个学生注册,并且注册的日期不一样)
注:为什么不一个Student对应一个Enrollment,或者一个Course对应一个Enrollment呢?
据博主的理解:这里仅仅是逻辑模型,我们通过日常的理解即可,一个学生可能注册多个课程,一个课程可能被多个学生注册。实际上在最终的存储中,由Student和Course共同确认一个Enrollment。
对比概念模型和逻辑模型:
概念模型并不能真正为我们提供存储数据的结构,它只代表业务实体及其关系。我们用它来帮助理解问题域,以便和域专家交流。
逻辑模型为我们的概念模型增加了更多细节,这样我们几乎了解什么结构或什么表需要用来存储数据。这里用到的实体,最终会以表格的形式出现在我们的数据库中。
实体模型是逻辑模型通过特定数据库技术的实现
使用逻辑数据模型,并在MySQL中创建一个实体模型。
主键是唯一标识给定表里每条记录的列。
最好为主键设置自动递增。
什么时候需要使用外键:对于一张表,想让其与另一张表产生联系时使用。
如何设置外键
在enrollments表中,student_id、course_id都是外键,分别引用了students、courses中的字段。分别为这两个外键添加主键,就变成了复合主键。
标准化是审计我们的涉及,并确保它遵循一些防止数据重复的预定义规则的这一过程。基本上有7条规则,也被称为七范式。
要求一行中的每个单元格都应该有单一值,且不.能出现重复列
courses表中的tag属性就不符合第一范式,tag将所有的标签以','分隔开,存储在一起。
解决方法:重新创建一个表tags
新建tags表后,需要在课程和标签表之间添加”多对多“关系,然而在关系型数据库中并没有 “多对多” 关系,只有“一对一” 和 “一对多” 关系。所以为了实现多对多关系,需要引入一张新的表,称为 “链接表” ,这张表会有两段 “一对多” 关系。
这张表不符合第二范式。instructor讲师列可能重复。
改为:
CREATE DATABASE IF NOT EXISTS database_name; -- 创建
DROP DATABASE IF EXISTS database_name; -- 删除
主键非空且唯一。
CREATE TABLE table_name (列名 数据类型 (PRIMARY KEY主键) (AUTO_INCREMENT自增) (UNIQUE唯一),列名 数据类型 (NOT NULL非空) (DEFAULT 0默认值为0)
);
ALTER TABLE table_nameADD 列名 数据类型 相关约束(NOT NULL/) (AFTER 在什么列后添加),-- 改变现有列MODIFY (COLUMN) 列名 数据类型,-- 删除现有列DROP 列名;
CREATE TABLE orders IF NOT EXISTS (order_id INT PRIMARY KEY,customer_id INT NOT NULL,FOREIGN KEY fk_orders_customers (customer_id)REFERENCES customers (customer_id)ON UPDATE CASCADE -- 父表customer_id更新时,子表customer_id级联更新ON DELETE NO ACTION -- 尝试删除一名顾客,而这名客户有过往订单
)
ALTER TABLE table_nameADD PRIMARY KEY (key_name, )DROP PRIMARY KEY,DROP FOREIGN KEY fk_subTableName_parentTableName,ADD FOREIGN KEY fk_subTableName_parentTableName (customer_id)REFERENCES parentTableName (customer_id)ON UPDATE CASCADEON DELETE NO ACTION;
当存储一个字符,比如ABC时,MySQL会使用字符集将每个字符转换为它的数值表示。因此字符集是将每个字符映射到数字的表。
SHOW CHARSET; -- 查看字符集
utf8mb3时utf8的别名,通过它可以存储几乎所有国际语言,这也是MySQL版本5或者更高版本使用的默认字符集
Default collation:排序规则就是一堆规则,决定了某类语言的字符如何排序。例如 utf8 字符集的默认排序规则是utf8mb3_general_ci,ci是case-insensitive(不区分大小写)的缩写,意思是MySQL在排序的时候,给与大小写同等优先级
Maxlen:MySQL存储每个字符的时候最多保留的字节数
CREATE TABLE table_name (CHARACTER SET lant1..
)
-- CREATE USER username(@(%.)选择限制用户的连接位置) (IDENTIFIED BY 'password')
CREATE USER john -- 可以从任何地方连接,毫无限制
CREATE USER john@127.0.0.1
CREATE USER john@localhost
CREATE USER john@域名 --(用户可以从该域中的任何计算机连接,但是无法从其子网连接)
CREATE USER john@'%.域名' --(包含子网)
CREATE USER john@127.0.0.1 IDENTIFIED BY '123456';
SELECT * FROM mysql.user;
DROP USER username@'域名/ip'
SET PASSWORD username = '新密码'; -- 不添加username,就是更改当前登录的用户密码
-- 1:web/desktop application
CREATE USER moon_app IDENTIFIED BY '1234';-- 授予权限:EXECUTE 执行存储过程的权限
GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE
ON sql_store.* -- ON 数据库.表 / 数据库.* 该数据库下所有的表
TO moon_app;-- 2:admin
GRANT ALL
ON sql_store.*
TO john;
SHOW GRANTS; -- 查看当前登录用户权限
SHOW GRANTS FOR john;
REMOVE CREATE VIEW ON sql_store.*
FROM username;
本文发布于:2024-01-28 07:04:06,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063966545659.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |