首页
关于
友链
推荐
肥啾解析
百度一下
肥啾GPT
Search
1
宝塔面板登录 phpMyAdmin 提示服务器和客户端上指示的HTTPS之间不匹配
379 阅读
2
Customer complaints evolve with in-car tech
265 阅读
3
JavaScript解析
194 阅读
4
所谓关系
185 阅读
5
解决Edge浏览器提示“此网站已被人举报不安全”
150 阅读
默认分类
网游架设
手机游戏
python
PHP
Mysql
VBA
C++
JAVASCRIPT
javascript基础
Oracle
生产管理
计划控制
ERP系统开发
APS排产
MES研究
考勤系统
CPA
财管
实务
经济法
战略
审计
税法
藏书架
古典名著
世界名著
编程秘籍
攻防渗透
经管书籍
大佬传经
风雅读物
考试相关
心情格言
拾玉良言
外文报刊
外刊随选
Facebook
Twitter
China Daily
软考
登录
Search
标签搜索
期刊读物
古文
何瑜明
累计撰写
196
篇文章
累计收到
154
条评论
首页
栏目
默认分类
网游架设
手机游戏
python
PHP
Mysql
VBA
C++
JAVASCRIPT
javascript基础
Oracle
生产管理
计划控制
ERP系统开发
APS排产
MES研究
考勤系统
CPA
财管
实务
经济法
战略
审计
税法
藏书架
古典名著
世界名著
编程秘籍
攻防渗透
经管书籍
大佬传经
风雅读物
考试相关
心情格言
拾玉良言
外文报刊
外刊随选
Facebook
Twitter
China Daily
软考
页面
关于
友链
推荐
肥啾解析
百度一下
肥啾GPT
搜索到
196
篇与
的结果
2026-01-19
数据库知识点
GRANT 子句是 SQL 中用于给数据库用户或角色授予权限的命令。 它是数据库权限管理的核心,控制着“谁能在什么对象上执行什么操作”。简单来说,它的作用就是:开门发钥匙。门: 数据库里的各种对象(如表、视图、数据库、函数等)。钥匙: 对这些对象执行的操作权限(如查看、插入、删除等)。发钥匙的人: 数据库管理员或拥有授权权限的用户。GRANT是标准SQL提供的授权语句,即通过把数据库对象的操作权限授予用户,用户具有对象上的操作权限才能进行相应的操作。视图是建立在基本表上的虚表,通过外模式/模式的映像,将视阁所提供的字段(外模式)指向基本表(模式)中的部分数据,用户通过视图所访问的数据只是对应基本表 中的部分数据,而无需给用户提供基本表中的全部数据,则视图外的数据对用户是不可见的,即受到了保护。存储过程是数据库所提供的一种数据库对象,通过存储过程定义一段代码,提供给应用程序调用来执行。从安全性的角度考虑,更新数据时,通过提供存储过程让第三方 凋用,将需要更新的数据传入存储过程,而在存储过程内部用代码分别对需要的多个表进行更新,从而避免了向第三方提供系统的表结构,保证了系统的数据安全。主要用途授予对数据库的访问权限:允许用户连接到一个数据库。授予对数据对象的操作权限:允许用户对特定的表、视图等进行增删改查。授予执行特定代码的权限:允许用户运行存储过程或函数。授予授予权限的权限:允许用户将自己获得的权限再授予其他人(使用 WITH GRANT OPTION)。GRANT 权限类型 ON 对象 TO 用户或角色 [WITH GRANT OPTION];权限类型{callout color="#f0ad4e"}SELECT: 查询数据INSERT: 插入新数据UPDATE: 更新现有数据DELETE: 删除数据ALL PRIVILEGES: 所有权限CREATE, DROP, ALTER: 对数据库或表结构的操作权限EXECUTE: 执行存储过程或函数USAGE: 使用模式、序列等对象的权限数据库对象权限 ├── 数据访问权限 │ ├── SELECT (读取) │ ├── INSERT (创建) │ ├── UPDATE (修改) │ └── DELETE (删除) │ ├── 结构修改权限 │ ├── ALTER (修改结构) │ ├── INDEX (创建索引) │ └── REFERENCES (外键约束) │ ├── 特殊操作权限 │ ├── EXECUTE (执行) │ └── TRUNCATE (清空) │ └── 管理权限 ├── GRANT OPTION (转授) └── WITH ADMIN OPTION (管理)对象可以是具体的 database_name.table_name可以是整个数据库 database_name.*可以是所有数据库 .用户或角色:一个或多个数据库用户名。角色名(现代数据库更推荐先授权给角色,再把角色分配给用户)。{/callout}授予用户 read_user 对 employees 表的只读权限: GRANT SELECT ON company.employees TO read_user; 授予用户 app_user 对 orders 表的完整数据操作权限: GRANT SELECT, INSERT, UPDATE, DELETE ON shop.orders TO app_user; 授予用户 admin_user 对 reports 数据库的所有权限,并允许其授权他人: GRANT ALL PRIVILEGES ON reports.* TO admin_user WITH GRANT OPTION; --WITH GRANT OPTION 是 SQL 授权语句中的一个可选子句,它允许被授权者(grantee)将自己获得的权限再次授予其他用户或角色。 允许用户 user1 连接到名为 mydb 的数据库: GRANT CONNECT ON DATABASE mydb TO user1; -- PostgreSQL 示例 创建一个只能查询特定视图的只读账户: GRANT SELECT ON my_schema.sales_summary_view TO reporting_user; 与 GRANT 对应的是 REVOKE 子句,用于收回已授予的权限。REVOKE INSERT, UPDATE ON shop.orders FROM app_user;注意事项与实践最小权限原则:只授予用户完成工作所必需的最小权限。不要随意使用 ALL PRIVILEGES。使用角色管理:对于复杂的权限管理,先创建角色(如 analyst, developer),将权限授予角色,再将角色分配给用户。这样更易于维护。定期审计:使用如 SHOW GRANTS FOR user_name;(MySQL)或 \dp(PostgreSQL)等命令检查现有权限。WITH GRANT OPTION 要慎用:这会导致权限链难以追踪和管理。权限生效:通常 GRANT 执行后权限立即生效,但有时用户需要重新登录才能激活。触发器 是一种特殊的存储过程,它在特定的事件(如 INSERT、UPDATE、DELETE)发生时自动执行。但并不是所有数据库操作都能激活触发器。(增删改)COMMIT 是"确认保存"的命令,它将事务中的所有更改永久写入数据库。要理解 COMMIT,必须先明白什么是 事务:事务是一组 SQL 操作,它们要么 全部成功,要么 全部失败,是一个不可分割的工作单元。事务的经典例子:银行转账-- 这是一个完整的事务,包含两个操作: 1. 从A账户扣款100元 2. 向B账户加款100元 -- 这两个操作必须同时成功或同时失败 -- 不能只扣款不加款,也不能只加款不扣款COMMIT 的作用机制事务的生命周期:开始事务 → 执行操作 → (可选:回滚ROLLBACK) → 提交COMMIT-- 1. 开始事务后,所有的修改都是临时的 BEGIN TRANSACTION; -- 开始事务 UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 临时修改 UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- 临时修改 -- 此时: -- - 你自己能看到修改后的数据 -- - 其他用户/会话看不到你的修改 -- - 如果系统崩溃,修改会丢失 -- 2. 使用COMMIT后,修改变成永久的 COMMIT; -- 确认保存 -- 此时: -- - 修改被永久写入磁盘 -- - 所有用户都能看到修改 -- - 即使系统崩溃,修改也不会丢失为什么需要 COMMIT?1.保证数据一致性(ACID原则)COMMIT 是 ACID 中 D(持久性) 的实现:A(原子性):事务的所有操作是一个整体C(一致性):事务前后数据库状态一致I(隔离性):事务之间互不干扰D(持久性):COMMIT 后数据永久保存2.提供"撤销"机会--在 COMMIT 之前,可以用 ROLLBACK 撤销所有操作: BEGIN TRANSACTION; -- 不小心删错了数据 DELETE FROM employees WHERE department = 'IT'; -- 发现错误!可以撤销 ROLLBACK; -- 所有删除操作被撤销,数据恢复 -- 或者确认无误后提交 -- COMMIT; -- 永久删除3.批量操作的性能优化-- 没有事务:每条INSERT都立即写入磁盘,性能差 INSERT INTO log_table VALUES (...); -- 立即写磁盘 INSERT INTO log_table VALUES (...); -- 立即写磁盘 -- ... 1000次 -- 使用事务:批量写入,性能大幅提升 BEGIN TRANSACTION; INSERT INTO log_table VALUES (...); INSERT INTO log_table VALUES (...); -- ... 1000次 COMMIT; -- 一次性写入磁盘,效率高视图视图是一个虚拟表,其内容由查询定义。它不存储数据本身,而是存储查询。当查询视图时,数据库引擎执行底层查询并返回结果。{callout color="#f0ad4e"}视图不存储数据,但可以通过视图访问数据" —— 这基本正确。视图本身通常不存储数据(物化视图除外,但标准SQL视图是虚拟的)。视图允许通过它访问底层表中的数据。"视图提供了一种数据安全机制" —— 视图可用于限制用户对特定行或列的访问,从而实现安全机制。例如,可以创建一个视图只显示某些列或满足某些条件的行,然后授予用户访问视图的权限,而不是底层表。"视图可以实现数据的逻辑独立性" —— 逻辑数据独立性是指应用程序不受数据库逻辑结构(如表结构)变化的影响。视图可以隐藏底层表的复杂变化,提供一致的接口。如果表结构改变,可以修改视图定义以保持相同的视图结构,从而使依赖于视图的应用程序无需修改。"视图能够提高对数据的访问效率" —— 视图本身是虚拟的,不存储数据。查询视图通常需要执行底层查询,可能涉及联接、过滤等,可能不会提高效率,有时甚至可能降低效率,因为额外的抽象层可能导致优化困难。但是,有些数据库支持物化视图,它们存储实际数据并可以提高查询性能。但一般来说,标准视图不会提高访问效率;事实上,它们可能引入性能开销。效率提升通常依赖于索引、物化视图等技术。{/callout}与 NOT IN 等价的操作符是 NOT EXISTS,但二者在 NULL 值处理 上有重要差异假设有两个表:员工 和 已离职员工。使用 NOT IN(注意 NULL 问题):SELECT * FROM 员工 WHERE 员工ID NOT IN (SELECT 员工ID FROM 已离职员工);如果 已离职员工 中有任意一行的 员工ID 为 NULL,则查询返回 空结果。使用 NOT EXISTS(安全写法):SELECT * FROM 员工 e WHERE NOT EXISTS (SELECT 1 FROM 已离职员工 d WHERE d.员工ID = e.员工ID);即使 已离职员工 中有 NULL,也能正确查询。<> ALL(与 NOT IN 同样存在 NULL 问题):SELECT * FROM 员工 WHERE 员工ID <> ALL (SELECT 员工ID FROM 已离职员工);聚合函数 是对一组值进行计算并返回单个值的函数,通常与 GROUP BY 子句一起使用,对数据行进行分组统计。常用聚合函数COUNT() - 计数-- 统计行数(包括NULL) SELECT COUNT(*) FROM 表名; -- 统计特定列非NULL值的数量 SELECT COUNT(列名) FROM 表名; -- 统计唯一值数量 SELECT COUNT(DISTINCT 列名) FROM 表名;SUM() - 求和-- 对数值列求和 SELECT SUM(金额) FROM 订单表; -- 忽略NULL值 SELECT SUM(单价 * 数量) FROM 明细表;AVG() - 平均值-- 计算平均值(忽略NULL) SELECT AVG(成绩) FROM 学生成绩; -- 包含NULL的处理 SELECT AVG(COALESCE(成绩, 0)) FROM 学生成绩;MAX() / MIN() - 最大值/最小值-- 最大值 SELECT MAX(价格) FROM 产品表; -- 最小值 SELECT MIN(入职日期) FROM 员工表;GROUP_CONCAT() (MySQL) / STRING_AGG() (PostgreSQL/SQL Server) / LISTAGG() (Oracle)-- MySQL: 将多行值连接成字符串 SELECT 部门, GROUP_CONCAT(员工姓名 SEPARATOR ', ') FROM 员工表 GROUP BY 部门; -- SQL Server SELECT 部门, STRING_AGG(员工姓名, ', ') FROM 员工表 GROUP BY 部门;STDDEV() / VARIANCE() - 标准差/方差-- 标准差 SELECT STDDEV(分数) FROM 考试成绩; -- 方差 SELECT VARIANCE(分数) FROM 考试成绩;SELECT列表规则-- 错误:非聚合列未包含在GROUP BY中 SELECT 部门, 员工姓名, AVG(工资) -- 员工姓名不在GROUP BY中 FROM 员工 GROUP BY 部门; -- 正确 SELECT 部门, 员工姓名, AVG(工资) FROM 员工 GROUP BY 部门, 员工姓名; -- 或者使用聚合函数处理员工姓名当使用 GROUP BY 分组时,SELECT 列表中只能包含:聚合函数(如 COUNT、SUM、AVG 等)GROUP BY 子句中出现的列常量或表达式(但必须基于上述1或2)逻辑解释:GROUP BY 将多行数据合并为一行,SELECT 列表必须确保每列在分组后只有一个确定的值。-- 假设员工表数据: 员工ID | 姓名 | 部门 | 工资 1 | 张三 | 销售部 | 5000 2 | 李四 | 销售部 | 6000 3 | 王五 | 技术部 | 7000 -- 如果按部门分组: 销售部:有张三(5000)、李四(6000) 两行 技术部:有王五(7000) 一行 问题:销售部分组中有"张三"和"李四"两个姓名,数据库不知道返回哪个SELECT包含未在GROUP BY中的列SELECT 部门, 姓名, -- 错误!每个部门有多个姓名,应该显示哪个? AVG(工资) as 平均工资 FROM 员工表 GROUP BY 部门;正确写法将列添加到 GROUP BY-- 同时按部门和姓名分组(这样每个组只有一个人) SELECT 部门, 姓名, AVG(工资) FROM 员工表 GROUP BY 部门, 姓名; -- 结果:每人一行,失去了分组统计的意义执行顺序-- SQL执行顺序 1. FROM/JOIN -- 确定数据源 2. WHERE -- 行级筛选 3. GROUP BY -- 分组 4. HAVING -- 组级筛选 5. SELECT -- 选择列 6. ORDER BY -- 排序 7. LIMIT/OFFSET -- 限制结果权限管理主体指可以被授予权限的实体。用户: 登录数据库的单个账户。角色: 一组权限的集合。将权限授予角色,再将角色授予用户,是管理权限的最佳实践。组(在某些数据库中如 SQL Server): 类似角色。客体指可以被操作的对象。层次结构通常为:服务器/实例 -> 数据库 -> 模式 -> 对象。对象包括:表、视图、存储过程、函数、序列等。权限定义了对某个客体可以执行的操作。主要分为两类:系统权限: 针对数据库或服务器本身的操作权限(如创建数据库、修改用户、查看服务器状态)。对象权限: 针对特定数据库对象的操作权限(如对某张表的 SELECT, INSERT, UPDATE, DELETE, EXECUTE 等)。SQL 中的主要集合操作符有以下几种:注意事项:列的数量和类型必须匹配:所有参与集合操作的 SELECT 语句必须有相同数量的列,且对应列的数据类型必须兼容。排序:可以在最后使用一个 ORDER BY 子句对整个结果排序。数据库支持:UNION 广泛支持。INTERSECT 和 EXCEPT 在 SQL Server、PostgreSQL、SQLite 中支持。Oracle 使用 MINUS 代替 EXCEPT。MySQL 5.7 及以下版本不支持 INTERSECT 和 EXCEPT,需用 JOIN 或子查询模拟。断言(Assertion) 是 SQL 标准中定义的一种完整性约束,用于声明数据库必须始终满足的全局条件(涉及一个或多个表)。如果任何数据修改操作(插入、更新、删除)导致断言条件为假,则该操作会被拒绝。特点:全局性:不依附于特定表,可跨多个表定义约束。自动维护:数据库自动检查并强制执行。复杂条件:可使用子查询、聚集函数等。语法CREATE ASSERTION <断言名称> CHECK (<条件>);通常使用以下方式替代断言:触发器(Triggers)触发器是一种特殊的存储过程,它与表相关联,当特定的数据修改事件发生在表上时,数据库会自动执行触发器中定义的SQL语句。触发器通常用于强制执行业务规则、维护数据完整性、审计数据变更触发器通常被定义为一组(一个或多个)SQL语句的集合,这些语句在特定事件(如INSERT、UPDATE、DELETE)发生时自动执行。这种“集合”意味着触发器可以包含多个SQL语句,这些语句作为一个整体在触发器被触发时执行。存储过程 通过封装数据修改操作来检查约束。应用层验证 在应用程序代码中保证数据完整性。与 CHECK 约束的区别触发器是一种特殊的数据库对象,它在特定事件发生时自动执行,用于实现复杂的业务规则、数据完整性约束和审计跟踪。触发器是什么?一段与表关联的 PL/SQL 或 T-SQL 代码在指定事件发生时自动触发执行依附于特定的表或视图触发器的三个核心要素:触发事件:INSERT、UPDATE、DELETE触发时机:BEFORE(之前)或 AFTER(之后)触发频率:行级(每行)或语句级(每次语句)触发器类型(按执行时机) 1. BEFORE 触发器 在数据修改操作之前执行,常用于: 数据验证 数据转换 防止非法操作 -- MySQL 示例:插入前检查工资 DELIMITER // CREATE TRIGGER check_salary_before_insert BEFORE INSERT ON Teachers FOR EACH ROW BEGIN IF NEW.salary < 3000 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '工资不能低于3000'; END IF; END // DELIMITER ; 2. AFTER 触发器 在数据修改操作之后执行,常用于: 审计日志 同步更新 级联操作 -- SQL Server 示例:记录删除日志 CREATE TRIGGER log_teacher_delete ON Teachers AFTER DELETE AS BEGIN INSERT INTO TeacherAudit (teacher_id, action, audit_time) SELECT deleted.teacher_id, 'DELETE', GETDATE() FROM deleted; END; 不同数据库的触发器语法 MySQL CREATE TRIGGER trigger_name {BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON table_name FOR EACH ROW BEGIN -- 触发器逻辑 END; Oracle CREATE OR REPLACE TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF} {INSERT | UPDATE | DELETE} ON {table_name | view_name} [FOR EACH ROW] DECLARE -- 变量声明 BEGIN -- 触发器逻辑 END; 触发器本身并不拥有独立的事务,它只是在已有事务中执行的一组操作。触发器是事务的一部分,而不是事务的控制者。触发器操作会随着主事务一起提交或回滚,不能自己决定事务的边界。-- 想象一个简单的UPDATE操作: BEGIN TRANSACTION; -- 事务开始 UPDATE Teachers SET salary = 6000 WHERE id = 101; -- 触发AFTER UPDATE触发器 -- 触发器中的操作在此执行 COMMIT; -- 事务结束,提交所有更改关键点: 触发器在 UPDATE 之后、COMMIT 之前执行,但触发器本身不能改变事务的边界。触发器不能包含事务控制语句的根本原因:职责分离:触发器负责数据完整性,事务控制由应用程序或存储过程负责事务一致性:保证所有操作要么全部成功,要么全部失败避免死锁和竞态条件:如果多个触发器各自控制事务,容易导致复杂并发问题可预测性:确保数据库行为一致,易于理解和维护记住:触发器是"乘客",存储过程/应用是"司机"乘客可以提醒司机(抛出异常)但不能抢方向盘(控制事务)最终去哪里(提交/回滚)由司机决定触发器不传递参数对数据库的更新,应采用事务的方式,以对应现实中的业务。用户在现实业务过程中通过调用事务程序,将事务程序交由DBMS来执行,DBMS通过其并发调度机制完成事务的并行执行。存储过程正是在服务器端所提供的功能调用,适用于编写更新数据库的事务程序。触发器是由更新语句来触发执行的,适用于数据的联动操作和复杂约束的实现,无法供应用程序主动调用。嵌入式SQL(Embedded SQL) 是一种将SQL语句直接嵌入到宿主编程语言(如C、C++、Java、COBOL等)中的技术,允许在传统编程语言中直接操作数据库。嵌入式SQL的语法元素声明段(Declare Section)连接数据库游标操作 游标是一种数据库对象,允许你逐行访问查询结果集,就像读书时使用书签一样,可以逐行“翻阅”数据结果。动态SQL
2026年01月19日
8 阅读
0 评论
0 点赞
2026-01-15
此内容被密码保护
加密文章,请前往内页查看详情
2026年01月15日
2 阅读
0 评论
0 点赞
2026-01-09
此内容被密码保护
加密文章,请前往内页查看详情
2026年01月09日
3 阅读
0 评论
0 点赞
2026-01-08
此内容被密码保护
加密文章,请前往内页查看详情
2026年01月08日
3 阅读
0 评论
0 点赞
2026-01-07
软工知识点
函数调用时实参向形式参数传递相应类型的值,则称为是传值调用。这种方式下形式参数不能向实参传递信息。实参可以是变量,也可以是常量和表达式。引用调用的实质是将实参变量的地址传递给形参,因此,形参是指针类型,而实参必须具有左值。变量具有左值,常量没有左值。被调用函数对形参的访问和修改实际上就是针对相应实际参数所作的访问和改变,从而实现形参和实参间双向传递数据的效果。{callout color="#f0ad4e"}传值调用(就像“复印一份”)做法:你把文件的完整复印一份,把这份复印件交给朋友。朋友的操作:他可以在复印件上任意涂改、做笔记。对你原件的影响:没有任何影响。你手里的原件还是原来那份,干干净净。在编程中的体现:函数内部修改的是“复印件”(形参),而外部的原始数据(实参)完全不变。实参可以是任何数据(变量、数字5、一个算式的结果)。引用调用(就像“共享电子文档链接”)做法:你把文件存储在云盘(如Google Docs),然后只把文件的访问链接(地址) 发给朋友。朋友的操作:他点击这个链接,打开的就是你电脑里的那个唯一原件。他做的任何修改都会直接保存到这份原件上。对你原件的影响:直接影响。你再打开文件,看到的就是他修改后的版本。在编程中的体现:函数内部通过“链接”(地址)直接操作外部的原始数据(实参)。为了实现这一点:实参必须是一个“有位置的变量”(就像一个实际存在的云盘文件)。你不能把一个纯数字(比如5)或者一句话的链接发给别人,因为这些东西没有“存储位置”可供修改。这也就是解析里说的,实参必须有 “左值” (可以简单理解为 “是一个可以存放东西的容器/位置”)。{/callout}为什么只有变量才有存储位置问题简单来说就是内存寻址的概念。计算机中,程序运行时,数据需要存储在内存中特定的位置(地址)。变量在程序中定义时,编译器或解释器会为它分配一块内存空间,因此变量有存储位置(地址)。而常量和表达式的结果(除非被赋给变量)通常是临时性的,它们可能存放在寄存器或临时栈空间,但程序通常不提供直接访问其地址的机制(尤其是常量,往往在编译时就确定了值,可能直接嵌入指令中,没有运行时内存地址)。对于引用调用(传递地址),需要实参有一个固定的、可寻址的内存位置,以便形参(指针)能够指向它,从而通过指针修改其内容。常量没有可修改的内存位置(常量通常存储在只读内存区或直接编码在指令中),表达式的结果是临时值,也没有持久的内存地址(除非先赋给变量)。因此,只有变量(或更广义的左值)才能进行引用传递。左值(lvalue)是一个历史术语,意指可以出现在赋值语句左边的表达式,即它标识了一个可存储对象的位置。变量是典型的左值。常量和算术表达式的结果是右值(rvalue),它们没有可标识的存储位置(或者说是临时值)。引用调用需要左值,因为需要取地址。举例:假设有函数 void f(int &x) { x = 10; }调用时:int a = 5; f(a); // 正确,a是变量,有地址f(5); // 错误,5是常量,没有可修改的地址f(a+1); // 错误,a+1是表达式结果,临时值,没有持久地址因此,引用调用要求实参必须是左值(变量)。
2026年01月07日
24 阅读
0 评论
0 点赞
1
...
7
8
9
...
40
0:00