数据库系统概论笔记(3)

第3章关系数据库标准语言SQL

数据库查询语言SQL:是关系数据库的标准语言。(功能包括查询,数据库模式的创建,数据库数据的插入、修改,数据库安全性完整性定义与控制)

3.1SQL概述

*SQL的特点:

  1. 综合统一
    SQL集数据定义语言(DDL)、数据操纵语言(DML)、数据控制语言(DCL)功能于一体
  2. 高度非过程化
    SQL进行数据操作时,只要提出“做什么”,而无需指明“怎么做”,因此无需了解存取路径。
  3. 面向集合的操作方式
    SQL采用集合操作方式
  4. 以同一种语法结构提供多种使用方式
    SQL即是独立的语言,又是嵌入式语言
  5. 语言简洁,易学易用
    核心功能只用9个动词

SQL的基本概念:
支持SQL的DBSM同样支持关系数据库的三级模式结构

基本表:本身独立存在的表,DBSM中一个关系对应一个基本表
存储文件:存储文件的逻辑结构组成了关系数据库的内模式
视图:从一个或几个基本表导出的表,本身不独立存储在数据库中,是虚表(数据库只存放视图的定义而不存放视图对应的数据)

3.2学生-课程数据库

略,翻书P79、80看那几张表

3.3数据定义


SQl标准不提供修改模式定义和视图定义的操作,若想修改,只能先删除再重建
一个DBSM的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象

模式的定义与删除:

  • 定义模式
    SQL中定义模式语句为:CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
    若没有指定<模式名>,那么<模式名>隐含为<用户名>;若找不到<用户名>对应的用户,则会报错
    定义模式实际上定义了一个命名空间,在这个空间中可以进一步定义该模式包含的数据库对象(基本表、视图、索引等)
    CREATE SCHEMA <模式名> AUTHORIZATION <用户名> [<表定义子句>|<视图定义子句>|<授权定义子句>];
    例:为用户ZHANG创建一个模式TEST,并且在其中定义一个表TAB1
CREATE SCHEMA TEST AUTHORIZATION ZHANG //无此行则默认在当前用户建立
CREATE TABLE TAB1(COL1 SMALLINT,
COL2 INT,
COL3 CHAR(20),
COL4 NUMERIC(10,3),
COL5 DECIMAL(5,2)
);
  • 删除模式
    SQL中删除模式语句为:DROP SCHEMA <模式名> <CASCADE|RESTRICT>;
    其中CASCADERESTRICT两者必选其一。
    选择CASCADE(级联),表示删除模式的同时把该模式中所有的数据库对象全部删除
    选择RESTRICT(限制),表示如果该模式中已经定义了下属的数据库对象(表、视图等),则拒绝该删除语句的执行,只有该模式中没有任何下属的对象时才能执行DROP SCHEMA语句

表的定义、删除与修改:

  • 定义基本表,使用CREATE TABLE语句
    列级完整性约束条件可以有PRIMARY KEY(主码)、UNIQUE(取唯一值,相当于候选码)、NOT NULL(不能为空)等
    表级完整性约束条件可以有FOREIGN KEY(<外码>) REFERENCE <被参照表>(<被参照列>)(定义外码)、PRIMARY KEY(<属性1>, <属性2>,...)(定义两个属性以上组成的主码)
CREATE TABLE <表名> (<列名> <数据类型> [列级完整性约束条件]
[, <列名> <数据类型> [列级完整性约束条件]]
...
[, <表级完整性约束条件>]);
  • 数据类型
    SQL中域的概念用数据类型来实现,定义时需要指明数据类型及其长度

  • 模式与表
    定义表时指定模式的三种方法

//方法一,在表名中显式给出模式名
CREATE TABLE "<模式名>".<表名>(...);
//方法二,在创建模式语句中同时创建表
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>
[<表定义子句>|<视图定义子句>|<授权定义子句>];
//方法三,设置所属的模式,再创建表(不必给出模式名)
SET search path TO "...", PUBLIC;
CREATE TABLE <表名>(...);
  • 修改基本表
    SQL中使用ALTER TABLE语句
ALTER TABLE <表名>
[ADD [COLUMN] <新列名> <数据类型> [完整性约束]] //增加新列/新列级完整性约束条件
[ADD <表级完整性约束>] //增加新表级完整性约束条件
[DROP [COLUMN] <列名> [CASCADE | RESTRICT]] //删除列
[DROP CONSTRAINT <完整性约束名> [RESTRICT | CASCADE]] //删除指定的完整性约束条件
[ALTER COLUMN <列名> <数据类型>]; //修改原有的列的定义(列名/列的数据类型)
  • 删除基本表
    SQL中用DROP TABLE语句
DROP TABLE <表名> [RESTRICT | CASCADE];

索引的建立与删除:
索引能加快查询速度,但索引占用一定的存储空间,过多的索引会增加数据库的负担
*常见的索引包括:顺序文件上的索引、B+树的索引、散列索引、位图索引

  • 建立索引
    SQL中使用CREATE INDEX
CREATE [UNIQUE] [CLUSTER] INDEX > <索引名>
ON <表名> (<列名> [<次序>] [, <列名> [<次序>]] ...);
/*
在表名指定的表的上建立该表的一列或多列的索引
<次序>可选 升序ASC / 降序DESC
UNIQUE 表明索引的每一个索引值只对应唯一的数据记录
CLUSTER 表明建立 索引 还是 聚簇索引
*/
  • 修改索引
    SQL中使用ALTER INDEX
ALTER INDEX <旧索引名> RENAME TO <新索引名>;
//将旧索引名重命名为新索引名
  • 删除索引
    SQL中使用DROP INDEX
DROP INDEX <索引名>;
//删除索引名指定的索引

3.4数据查询

  • 数据查询一般格式
    SQL中使用SELECT语句
SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] ...
FROM <表名或视图名> [, <表名或视图名> ...] | (<SELECT语句>) [AS] <别名>
[WHERE <条件表达式>]
[GROUP BY <列名1> [<HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC | DESC]];
/*
FROM 指定基本表/视图/派生表
WHERE 从中找到满足条件的元组
SELECT 选出元组中的属性值形成结果表 DISTINCT 在此基础上消除重复行(不添加默认为ALL)
GROUP BY 按<列名1>的值进行分组(值相等分为一组) HAVING 在此基础上挑选出符合条件的组
ORDER BY 结果表按<列名2>的值进行升序或降序排列
*/

单表查询

  • 选择表中的若干
//查询指定列
SELECT <目标列表达式> [,<目标列表达式>] ...
...
//查询全部列
SELECT *
...
//查询经过计算的值
与查询指定列类似,<目标列表达式>可以是表达式(比如数值+-x÷、列名小写LOWER(<列名>)、修改列名(空格+想改的名字))
操作不会改变原数据,只会改变结果表
  • 选择表中的若干元组
//消除取值重复的行(使用DISTINCT
SELECT DISTINCT <目标列表达式> [,<目标列表达式>] ...
...
//查询满足条件的元组(使用WHERE
...
WHERE <列名> <比较运算符> <比较的值> //比较大小
WHERE [NOT] BETWEEN ... AND //在(不在)某一范围
WHERE <列名> [NOT] IN (<属性值> [,<属性值>] ...) //属性值属于指定集合
WHERE <列名> [NOT] LIKE '<匹配串>' [ESCAPE '<换码字符>'] //匹配字符串
WHERE <列名> = '<匹配串>' //匹配无通配符的字符串
/*<匹配串>可包含通配符 % 和 _
% 代表任意长度(>=0)的字符串
_ 代表任意单个字符
若要匹配通配符,则自定义转义字符放在通配符前*/
WHERE <列名> IS [NOT] NULL //查询空值(非空值)
WHERE <查询条件> [OR|AND <查询条件>] ... //连接多个查询条件

  • ORDER BY子句
    用来排序
//默认是升序ASC,降序要手动声明DESC
//排列时与属性的声明的顺序有关,先排前面的属性的值,再排后面的属性的值(前面的属性值相同时)
ORDER BY <属性名> [ASC | DESC] [,<属性名> [ASC | DESC] ]
  • 聚集函数
    聚集函数用来方便用户检索
    聚集函数遇到空值时,除COUNT (*)外,都跳过空值而只处理非空值
    聚集函数只能用于SELECT子句和GROUP BY中的HAVING子句
COUNT(*) //统计元组的个数
COUNT( [DISTINCT | ALL] <列名>) //统计一列中值的个数
SUM( [DISTINCT | ALL] <列名>) //计算一列值的总和(此列必须是数值型)
AVG( [DISTINCT | ALL] <列名>) //计算一列值的平均值(此列必须是数值型)
MAX( [DISTINCT | ALL] <列名>) //求一列值中的最大值
MIN( [DISTINCT | ALL] <列名>) //求一列值中的最小值
//指定 DISTINCT 短语,则表示计算时取消指定列中的重复值
//指定 ALL 短语或不指定(默认),则表示不取消重复值
  • GROUP BY子句
    GROUP BY子句将查询结果按某一列或多列的值分组,值相等的为一组
    分组的目的是细化聚集函数的作用对象
    分组后聚集函数将作用于每一个组,即每一个组都有一个函数值
    WHERE子句与HAVING短语的区别是作用对象不同
    WHERE子句作用于基本表或视图
    HAVING短语作用于组
GROUP BY <列名> [,<列名>]...
[HAVING <条件表达式(可用聚集函数)>]

连接查询

连接查询:一个查询同时涉及两个以上的表

  • 等值与非等值连接查询
    连接条件/连接谓词:连接查询的WHERE子句中用来连接两个表的条件
    连接谓词中的列名称为连接字段,各连接字段的类型必须是可比的
    把目标列中重复的属性列去掉则为自然连接
//若属性名在参与连接的各表是唯一的则可以忽略表名前缀
SELCTE [<表名>.]<列名> [,[<表名>.]<列名>]...
//若只有一个 * 且没有没有 WHERE 子句,则认为是对 FROM 中的表作笛卡尔积
SELCT *
FROM ....
//作θ连接
//当运算符为 = 时称为等值连接,其他运算符称为非等值连接
//WHERE可以有连接谓词和选择谓词的复合条件
WHERE [<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
//连接谓词的其它形式
WHERE [<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名3>.]<列名3>
  • 自身连接
    自身连接:一个表与自己进行连接
一般要对同一个表进行不同的命名来实现自身连接
例:
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno=SECOND.Cno;
  • 外连接
    把悬浮元组保存在结果关系中,没有值的属性填上NULL
//左连接
FORM <表名> LEFT OUTER JOIN SC ON (<连接>) //现在一般把连接条件写在FROM中(ON后括号内表示出来)
//右连接
FORM <表名> RIGHT OUTER JOIN SC ON (<连接>)
//全连接
FORM <表名> ALL OUTER JOIN SC ON (<连接>)
  • 多表连接
    两个以上的表进行连接
例:
SELECT ...
FROM Student,SC,Course
WHERE ...
//过程是先将Student与SC连接,结果表再与Course连接

嵌套查询

一个SELECT-FROM-WHERE语句称为一个查询块
嵌套查询:将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询
SQL允许多层嵌套查询
子查询的SELECT语句中不能使用ORDER BY子句,ORDER BY子句只能对最终查询结果排序

  • 带有IN谓词的子查询
先分步来完成此查询,然后再构造嵌套查询
例:
//查询与“刘晨”在同一个系学习的学生
//解法一
SELCET Sno,Sname,Sdept //查找所有在CS系学习的学生
FROM Student
WHERE Sdept IN(
SELECT Sdept //确定“刘晨”所在的系名CS
FROM Student
WHERE Sname='刘晨'
);
//子查询的条件不依赖于父查询,称为不相关子查询
//有些嵌套查询可以用连接运算替代,有些是不能替代的
SELCET Sno,Sname,Sdept
FROM Student S1, Student S2
WHERE S1.Sdept=S2.Sdept AND S2.Sname='刘晨';
  • 带有比较运算符的子查询
例:
//找出每个学生超过他自己选修课程平均成绩的课程号
SELECT Sno,Cno
FROM SC x
WHERE Grade >=(
SELECTE AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno
);
//子查询的查询条件依赖于父查询,这类查询称为相关子查询(x.Sno与父查询有关)
//内层查询每次从外层查询的x中取出一个元组进行WHERE子句的连接
//求解相关子查询不能像求解不相关子查询那样一次将子查询求解出来,然后求解父查询
//内层查询由于与外层查询有关,因此必须反复求值
  • 带有ANY(SOME)或ALL谓词的子查询
    子查询返回单值可用比较运算符,返回多值必须要用ANY(有些系统用SOME)或ALL,使用ANY或ALL时必须同时使用比较运算符
    ANY(SOME):查询结果中存在某个值满足比较条件即为TRUE,否则为FALSE
    ALL:所有查询结果都满足比较条件才为TRUE,否则为FALSE
    一般的ANY和ALL都能用聚集函数代替
例:
//查询非计算机系中比计算机系任意一个学生年龄小的学生姓名和年龄
//使用ANY
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY(
SELECTE Sage
FROM Student
WHERE Sdept='CS'
);
//等价的聚集函数写法
SELECT Sname,Sage
FROM Student
WHERE Sage < (
SELECTE MAX(Sage)
FROM Student
WHERE Sdept='CS'
);
  • 带有EXISTS谓词的子查询
    EXISTS代表存在量词,带有EXISTS谓词的子查询不返回任何数据,只产生true或false
    使用EXISTS,若内层查询结果非空,则外层的WHERE子句返回true,否则返回false(NOT EXISTS相反)
    由EXISTS引出的子查询,其目标列表达式一般用*(列名无实际意义)
    IN谓词、比较运算符、ANY、ALL谓词引出的子查询都能用EXISTS/NOT EXISTS谓词的子查询等价代替,反之却不一定可以
    用EXISTS实现全称量词(x)Px(P)
    用EXISTS实现逻辑蕴含(y)pqy(pq)
例:
(实现全称量词)
查询 选修了全部课程 的学生姓名 ↓
//查询 不存在有未选修课程 的学生姓名 ↓
//查询 (NOT EXISTS 未选修) 的学生姓名 ↓
//查询 (NOT EXISTS (NOT EXISTS 选修了的课程)) 的学生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS(
SELECT *
FROM Course
WHERE NOT EXISTS(
SELECT *
FROM SC
WHERE Sno=Student.Sno AND
Cno=Course.Cno
)
)
(实现逻辑蕴含)
查询至少选修了学生201215122选修的全部课程的学生号码
//p代表“学生201215122选修了课程y”,q代表“学生x选修了课程y”,即求(∀y)p->q
//转换成 ┐∃y(p∧┐q)
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS(
SELECT *
FROM SC SCY
WHERE SCY.Sno='201215122' AND
NOT EXISTS(
SELECT *
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND
SCZ.Cno=SCY.Cno
)
);

集合查询

集合操作包括:并UNION、交INTERSECT、差EXCEPT
参与集合操作的各查询结果的列数必须相同,对应项的数据类型也必须相同

//MySql不支持交、差操作
//SELECT-FROM-WHERE
UNION/INTERSECT/EXCEPT
//SELECT-FROM-WHERE
例:
查询既选修了课程1又选修了课程2的学生
SELECT Sno
FROM SC
WHERE Cno='1'
INTERSECT
SELECT Sno
FROM SC
WHERE Cno='2'
//另一种写法
SELECT Sno
FROM SC
WHERE Cno='1' AND
Sno IN(
SELECT Sno
FROM SC
WHERE Cno='2'
);

基于派生表的查询

子查询可以出现在FROM子句中,生成的临时派生表成为主查询的查询对象

//MySql不支持
例:
查询每个学生超过他自己选修课程平均成绩的课程号
SELECT Sno,Cno
FROM SC,(SELECT Sno,Avg(Grade) FROM SC GROUP BY Sno)
[AS] Avg_sc(avg_sno,avg_grade)
WHERE SC.Sno=Avg_sc.avg_sno AND
SC.Grade>=Avg_sc.avg_grade;
查询所有选修了1号课程的学生姓名
SELECT Sname
FROM Student,(SELECT Sno FROM SC WHERE Cno='1') [AS] SC1
WHERE Student.Sno=SC1.Sno;
//默认派生表的属性列为子查询SELECT子句后的列名
//AS可省略,但必须有别名

3.5数据更新

数据更新的3种操作:添加若干行数据、修改表中的数据、删除表中的若干行数据

插入数据

  • 插入元组
    功能:将新元组插入指定表中
    INTO子句指明了表名
    INTO子句没有指明任何属性列名,则新插入的元组必须在每个属性列上有值,且顺序要一致
    INTO子句指明了属性列名,则亦相应指明了新增加的元组在哪些属性上要赋值,顺序可以与CREATE TABLE的不一样,INTO子句上没指明的属性列则会取空值
    VALUE子句对新元组的各属性赋值,字符串常数要用单引号括起来
//一般格式:
INSERT
INTO <表名> [(<属性列1> [,<属性列2>] ...)]
VALUES (<常量1> [,<常量2>] ...);
  • 插入子查询结果
    子查询可以嵌套在INSERT语句中以生成要插入的批量数据
//一般格式
INSERT
INTO <表名> [(<属性列1> [,<属性列2>...])
子查询;

修改数据

修改数据又称更新操作
功能:修改指定表中满足WHERE子句条件的元组(用SET子句给出的值作相应取代),若省略WHERE子句,则表示要修改表中所有的元组

//一般格式
UPDATE <表名>
SET <列名>=<表达式> [,<列名>=<表达式>]...
[WHERE <条件>];
1. 修改某个元组的值
将学生201215121的年龄改为22
UPDATE Student
SET Sage=22
WHERE Sno='201215121';
2. 修改多个元组的值
将所有的学生的年龄增加1
UPDATE Student
SET Sage=Sage+1;
3.带查询的修改语句
将计算机科学系全体学生的成绩置零
UPDATE SC
SET Grade=0
WHERE Sno IN(
SELETE Sno
FROM Student
WHERE Sdept='CS'
);

删除数据

功能:从指定表中删除满足WHERE子句条件的所有元组,若省略WHERE则表示删除表中全部元组,但表的定义仍在字典中
注意:DELETE语句删除的是表中的数据,而不是关于表的定义

//一般格式
DELETE
FROM <表名>
[WHERE <条件>];
1. 删除某个元组的值
删除学号为201215121的学生记录
DELETE
FROM Student
WHERE Sno='201215121';
2. 删除多个元组的值
删除所有学生的选课记录
DELETE
FROM SC
3.带查询的删除语句
删除计算机系所有学生的选课记录
DELETE
FROM SC
WHERE Sno IN(
SELETE Sno
FROM Student
WHERE Sdept='CS'
);

3.6空值的处理

空值是一个特殊的值,含有不确定性

  • 空值的产生:插入、修改、外连接、空值的关系运算等都可能会产生空值
  • 空值的判断:用IS NULLIS NOT NULL来表示
  • 空值的约束条件:属性定义中有NOT NULL,加了UNIQUE限制的属性,码属性等不能取空值,外码可以取空值
  • 空值的算术、比较和逻辑运算:
    空值与另一个值的算术运算结果为空值
    空值与另一个值的比较运算结果为UNKNOWN
    有了UNKNOWN后,传统的逻辑运算中的二值逻辑就扩展成了三值逻辑

    注:增删改都注意要满足3个完整性条件

3.7视图

定义:是从一个或几个基本表(或视图)导出的表,只存放定义不存储数据,是一个虚表

定义视图

  • 建立视图
    CREATE VIEW语句只是把视图的定义存入数据字典,并不执行子查询中的SELECT语句
    子查询可以是任意的SELETE子句,是否可以含有ORDER BY子句和DISTINCT短语,则取决于具体的系统实现
    WITH CHECK OPTION表示对视图进行更新、插入、删除操作时要保证对应的行满足视图中定义的谓词条件(子查询的条件表达式)
    视图的属性列名必须全部指定或全部省略
    必须明确指定组成视图的所有列名的三种情况:
    1)某个目标列是聚集函数或表达式
    2)多表连接是选出了几个同名列作为视图的字段
    3)为某个列启用新的名字
//一般格式
CREATE VIEW <视图名> [(<列名> [,<列名>] ...)]
AS <子查询>
[WITH CHECK OPTION];
//关于WITH CHECK OPTION
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS'
WITH CHECK OPTION;
//之后对该视图进行增删改操作时,关系数据库管理系统会自动加上Sdept='IS'的条件
行列子集视图:若视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,则称这类视图为行列子集视图

视图可以建立在一个或多个基本表上,也可以建立在一个或多个已定义好的视图上,或建立在基本表与视图上

虚拟列:根据应用需求在视图中设置的一些派生属性列,而这些列在基本表中并不实际存在
带表达式的视图:带虚拟列的视图
CREATE VIEW BT_S(Sno,Sname,Sbirth)
AS
SELECT Sno,Sname,2021-Sage
FROM Student;
分组视图:带有聚集函数和GROUP BY子句的查询来定义的视图
CREATE VIEW S_G(Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
  • 删除视图
    删除视图后视图定义将从数据字典中删除
    若该视图上还导出了其他视图,则普通的删除会拒绝执行,要用级联删除把其与其导出的表都删除
//格式
DROP VIEW <视图名> [CASCADE];
//CASCADE是级联删除

查询视图

视图消解(一转换过程):从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,再执行修正了的查询

1:视图消解的一个例子
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20l
↓ 转换成对基本表的查询
SELECT Sno,Sage
FROM Student
WHERE Sdept='IS' AND Sage<20;
2:多数数据库系统对行列子集视图的查询均能进行正确转换,但对非行列子集视图的查询不一定能做转换(转换后查询出错)
SELECT *
FROM S_G
WHERE Gavg>=90
语法错误!因为定义视图时,Gavg是一聚集函数的“代表”(转换后会变成聚集函数),不能用于WHERE
修正:应该直接对基本表进行查询
SELECT *
FROM (
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno) AS S_G(Sno,Gavg)
WHERE Gavg>=90;
//此时的Gavg是一派生表的属性列,与聚集函数无关,可以用WHERE

视图定义后将保存在数据字典中,而派生表执行完后即被删除

更新视图

更新包括插入、删除和修改
对视图进行的修改最后会转换为对基本表的修改
在定义了WITH CHECK OPTION的视图中更新时,只有符合视图定义的条件的操作才会执行

1:修改视图的例子
UPDATE IS_Student
SET Sname='刘辰'
WHERE Sno='201215121'
↓ 转换成对基本表的修改
UPDATE Student
SET Sname='刘辰'
WHERE Sno='201215121' AND Sdept='IS';
2:视图更新失败的例子
//视图的定义
CREATE VIEW S_G(Sno,Gave)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
//视图修改
UPDATE S_G
SET Gavg=90
WHERE Sno='201215121';
错误!因为系统不能修改各科成绩使平均成绩为90(Gavg不是属性不能直接修改)

一般地,行列子集视图可更新,其它子图有些理论上可更新
不允许更新和不可更新是两个不同的概念

视图的作用

  • 简化用户操作
  • 可以从多种角度看待同一数据
  • 对重构数据库提供了一定程度的逻辑独立性
  • 对机密数据提供安全保护
  • 更清晰地表达查询
posted @   kksk43  阅读(455)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
特效
黑夜
侧边栏隐藏
点击右上角即可分享
微信分享提示