详细介绍:SQL中的CTE(公用表表达式)完全指南:从入门到精通

news/2025/10/28 17:05:52/文章来源:https://www.cnblogs.com/gccbuaa/p/19172266

在SQL的世界里,有一个功能经常被初学者忽视,但却是高手们最爱用的工具,那就是CTE(Common Table Expression,公用表表达式)。今天我们就来深入探讨一下这个强大的功能,看看它为什么能让复杂的SQL查询变得清晰易懂。

什么是CTE?为什么要用它?

CTE说白了就是一个临时的、有名字的查询结果集。你可以把它想象成一个只在当前查询中存在的"临时视图"。一旦查询执行完毕,这个CTE就消失了,不会在数据库中留下任何痕迹。

可能有人会问,我用子查询不也能达到同样的效果吗?确实,从功能上来说,CTE和子查询很多时候是可以互换的。但是CTE的优势在于它让代码更容易阅读、理解和维护。想象一下,如果你有一个嵌套了三四层的子查询,读起来会有多痛苦?而用CTE,你可以把这个复杂的查询分解成几个清晰的步骤,每个步骤都有一个有意义的名字。

让我先给你看一个最简单的CTE例子:

WITH customer_totals AS (
SELECT
CustomerID,
SUM(Amount) AS total_sales
FROM Orders
GROUP BY CustomerID
)
SELECT *
FROM customer_totals
WHERE total_sales > 10000;

在这个例子中,我们先用CTE定义了一个叫customer_totals的临时结果集,它计算了每个客户的总销售额。然后在主查询中,我们就可以像使用普通表一样使用这个CTE,筛选出销售额超过10000的客户。

CTE的基本语法

CTE的语法其实很简单,就是用WITH关键字开头,后面跟着CTE的名字,然后用AS,最后在括号里写查询语句:

WITH cte_name AS (
SELECT column1, column2
FROM table_name
WHERE condition
)
SELECT *
FROM cte_name;

如果你需要定义多个CTE,用逗号分隔就可以了:

WITH
first_cte AS (
SELECT ...
),
second_cte AS (
SELECT ...
),
third_cte AS (
SELECT ...
)
SELECT * FROM third_cte;

这里有一个重要的规则:后面定义的CTE可以引用前面定义的CTE,但反过来不行。这就像你在写程序时,后面的代码可以使用前面定义的变量,但前面的代码不能使用后面才定义的变量。

实战案例:订单支付分析

现在让我们看一个真实的业务场景。假设我们有一个电商系统,有订单表(Orders)和支付表(Payments)。一个订单可能会有多次支付记录(比如用户分多次付清一个订单),我们需要统计每个客户的总订单金额和未付清的订单数量。

这个问题听起来简单,但实现起来有几个难点:

第一,一个订单可能对应多条支付记录,我们需要先把这些支付记录汇总,算出每个订单一共付了多少钱。

第二,有些订单可能根本没有支付记录,我们需要把这些订单也考虑进去,把它们的已付金额当作0。

第三,我们要判断一个订单是否"未付清",就是比较总支付金额是否小于订单金额。

第四,最后还要按客户汇总,算出每个客户的总订单金额和未付清订单数。

让我们看看数据结构:

CREATE TABLE Orders (
OID INT PRIMARY KEY,
CustomerID INT NOT NULL,
Amount DECIMAL(10,2) NOT NULL
);
CREATE TABLE Payments (
OID INT NOT NULL,
Paid DECIMAL(10,2) NOT NULL
);

然后插入一些测试数据:

INSERT INTO Orders (OID, CustomerID, Amount) VALUES
(100, 1, 120.00),  -- 客户1的订单,需要付120元
(101, 1,  80.00),  -- 客户1的另一个订单,需要付80元
(102, 2, 200.00),  -- 客户2的订单
(103, 2,  50.00),  -- 客户2的另一个订单
(104, 3,  75.00);  -- 客户3的订单,完全没付款
INSERT INTO Payments (OID, Paid) VALUES
(100, 70.00),      -- 订单100第一次付款70元
(100, 50.00),      -- 订单100第二次付款50元,总共付清了120元
(101, 20.00),      -- 订单101只付了20元,还差60元
(102, 200.00),     -- 订单102付清了
(103, 25.00);      -- 订单103只付了25元,还差25元
-- 注意订单104没有任何支付记录

方案一:使用CTE解决

使用CTE,我们可以把这个复杂的问题分解成三个清晰的步骤:

WITH pay AS (
-- 第一步:把每个订单的多次支付汇总成一个总金额
SELECT OID, SUM(Paid) AS paid_total
FROM Payments
GROUP BY OID
),
per_order AS (
-- 第二步:把订单表和支付汇总表连接起来,标记每个订单是否未付清
SELECT
o.CustomerID,
o.OID,
o.Amount,
COALESCE(p.paid_total, 0) AS paid_total,
CASE
WHEN COALESCE(p.paid_total, 0) < o.Amount THEN 1
ELSE 0
END AS is_unpaid
FROM Orders o
LEFT JOIN pay p ON p.OID = o.OID
)
-- 第三步:按客户汇总
SELECT
CustomerID,
SUM(Amount) AS total_order_amount,
SUM(is_unpaid) AS num_unpaid_orders
FROM per_order
GROUP BY CustomerID
ORDER BY CustomerID;

让我们一步一步分析这个查询:

第一个CTE叫pay,它的作用是把支付表中的多条记录汇总。比如订单100有两条支付记录(70元和50元),这个CTE会把它们加起来,得到120元。执行完这一步后,pay的结果会是这样:

OID | paid_total
----|------------
100 | 120.00
101 | 20.00
102 | 200.00
103 | 25.00

注意订单104不在这个结果里,因为它根本没有支付记录。

第二个CTE叫per_order,它把订单表和刚才的pay表用LEFT JOIN连接起来。LEFT JOIN很重要,因为它保证了即使一个订单没有支付记录,这个订单也会出现在结果里,只不过支付金额会是NULL。我们用COALESCE(p.paid_total, 0)把NULL转换成0,这样方便后续计算。然后用CASE语句判断这个订单是否未付清:如果已付金额小于订单金额,is_unpaid就是1,否则是0。这个CTE的结果会是:

CustomerID | OID | Amount  | paid_total | is_unpaid
-----------|-----|---------|------------|----------
1          | 100 | 120.00  | 120.00     | 0
1          | 101 | 80.00   | 20.00      | 1
2          | 102 | 200.00  | 200.00     | 0
2          | 103 | 50.00   | 25.00      | 1
3          | 104 | 75.00   | 0.00       | 1

最后一步就简单了,我们按CustomerID分组,把每个客户的订单金额加起来,把is_unpaid标记加起来就得到了未付清订单的数量。最终结果是:

CustomerID | total_order_amount | num_unpaid_orders
-----------|-------------------|------------------
1          | 200.00            | 1
2          | 250.00            | 1
3          | 75.00             | 1

客户1有两个订单,总共200元,其中订单101未付清。客户2也有两个订单,总共250元,订单103未付清。客户3有一个订单75元,完全没付款。

方案二:使用子查询解决

同样的问题,我们也可以用子查询来解决。不过你马上就会发现,代码的可读性会差很多:

SELECT
o.CustomerID,
SUM(o.Amount) AS total_order_amount,
SUM(
CASE
WHEN (
SELECT COALESCE(SUM(p.Paid), 0)
FROM Payments p
WHERE p.OID = o.OID
) < o.Amount THEN 1
ELSE 0
END
) AS num_unpaid_orders
FROM Orders o
GROUP BY o.CustomerID
ORDER BY o.CustomerID;

这个查询在功能上和CTE方案完全等价,但你看出区别了吗?子查询方案把所有的逻辑都塞在了一个SELECT语句里。那个嵌套在CASE语句中的子查询,需要仔细读好几遍才能理解它在干什么。而且这个子查询是一个关联子查询,对于Orders表的每一行,它都要执行一次,这在某些情况下可能会影响性能。

我们还可以用另一种子查询的写法,在FROM子句中使用派生表:

SELECT
o.CustomerID,
SUM(o.Amount) AS total_order_amount,
SUM(
CASE
WHEN COALESCE(p.paid_total, 0) < o.Amount THEN 1
ELSE 0
END
) AS num_unpaid_orders
FROM Orders o
LEFT JOIN (
SELECT OID, SUM(Paid) AS paid_total
FROM Payments
GROUP BY OID
) p ON p.OID = o.OID
GROUP BY o.CustomerID
ORDER BY o.CustomerID;

这个版本比关联子查询好一些,至少把支付汇总的逻辑单独提取出来了。但问题是,这个派生表没有名字(或者说它的名字只是一个别名p),如果你的查询更复杂,有多个派生表,很容易搞混它们各自的作用。

对比一下CTE版本,每个步骤都有一个清晰的名字:pay表示支付汇总,per_order表示每个订单的详细信息。当你几个月后回来看这段代码时,CTE版本会让你立刻明白每一步在做什么。

多个CTE的链式使用

CTE的强大之处在于你可以定义多个CTE,后面的CTE可以引用前面的CTE。这就像搭积木一样,一步一步构建出复杂的查询逻辑。

让我们看另一个例子:课程先修课程检查。假设有一个选课系统,某些课程有先修课程要求。我们需要找出那些选了课但是没有完成先修课程的学生。

数据结构是这样的:

CREATE TABLE Enrollments (
StudentID INT NOT NULL,
CourseID  VARCHAR(16) NOT NULL,
Semester  CHAR(6) NOT NULL
);
CREATE TABLE Prereqs (
CourseID    VARCHAR(16) NOT NULL,
ReqCourseID VARCHAR(16) NOT NULL
);

Enrollments表记录了学生的选课信息,包括学生ID、课程ID和学期。Prereqs表定义了先修课程关系,比如DATA226需要先完成DATA201和DATA200。

测试数据:

INSERT INTO Prereqs (CourseID, ReqCourseID) VALUES
('DATA226','DATA201'),
('DATA226','DATA200'),
('DATA300','DATA226');
-- 学生1:选了DATA226(2025A学期),但只完成了DATA201,没完成DATA200
INSERT INTO Enrollments VALUES
(1,'DATA201','2024A'),
(1,'DATA201','2024B'),   -- 重修
(1,'DATA226','2025A');
-- 学生2:选了DATA226,两门先修课都完成了
INSERT INTO Enrollments VALUES
(2,'DATA200','2024A'),
(2,'DATA201','2024B'),
(2,'DATA226','2025A');
-- 学生3:选了DATA226,但没有任何先修课程记录
INSERT INTO Enrollments VALUES
(3,'DATA226','2025A');

CTE方案:逐步构建逻辑

WITH current AS (
-- 第一步:去重,得到当前所有选课记录
SELECT DISTINCT StudentID, CourseID, Semester
FROM Enrollments
),
needs AS (
-- 第二步:找出每个选课需要哪些先修课程
SELECT
c.StudentID,
c.CourseID,
c.Semester,
r.ReqCourseID
FROM current c
JOIN Prereqs r ON r.CourseID = c.CourseID
),
prior AS (
-- 第三步:去重,得到所有历史完成的课程
SELECT DISTINCT StudentID, CourseID, Semester
FROM Enrollments
),
joined AS (
-- 第四步:检查每个先修课程要求是否满足
SELECT
n.StudentID,
n.CourseID,
n.Semester,
n.ReqCourseID,
MAX(CASE WHEN p.StudentID IS NOT NULL THEN 1 ELSE 0 END) AS has_prior
FROM needs n
LEFT JOIN prior p
ON p.StudentID = n.StudentID
AND p.CourseID = n.ReqCourseID
AND p.Semester < n.Semester
GROUP BY n.StudentID, n.CourseID, n.Semester, n.ReqCourseID
)
-- 第五步:找出有任何一个先修课程未完成的选课记录
SELECT DISTINCT StudentID, CourseID, Semester
FROM joined
GROUP BY StudentID, CourseID, Semester
HAVING SUM(CASE WHEN has_prior = 0 THEN 1 ELSE 0 END) > 0;

这个查询看起来比较长,但每一步都很清晰:

第一步current把选课记录去重,因为可能有重复数据。

第二步needs把每个学生的当前选课和它所需的先修课程连接起来。比如学生1选了DATA226,这一步会产生两条记录:学生1需要DATA201,学生1需要DATA200。

第三步prior得到所有历史完成的课程记录。

第四步joined是关键,它用LEFT JOIN检查每个先修课程要求是否被满足。如果学生在之前的学期完成了这门先修课程,p.StudentID就不是NULL,has_prior就是1;否则是0。

最后一步找出那些至少有一个先修课程未完成的记录(SUM(CASE WHEN has_prior = 0 ...)。

子查询方案:双重NOT EXISTS

同样的逻辑,用子查询可以这样写:

SELECT DISTINCT e.StudentID, e.CourseID, e.Semester
FROM Enrollments e
WHERE EXISTS (
SELECT 1
FROM Prereqs r
WHERE r.CourseID = e.CourseID
AND NOT EXISTS (
SELECT 1
FROM Enrollments prior
WHERE prior.StudentID = e.StudentID
AND prior.CourseID = r.ReqCourseID
AND prior.Semester < e.Semester
)
);

这个查询用了双重嵌套的EXISTS子查询。外层的EXISTS检查这门课是否有先修课程要求,内层的NOT EXISTS检查学生是否完成了该先修课程。如果有任何一个先修课程没完成,NOT EXISTS就为真,整个条件就满足。

从逻辑上说,这个子查询版本其实更简洁,也可能性能更好。但问题是它的可读性较差,特别是双重嵌套的EXISTS让人需要花点时间理解。而CTE版本虽然代码行数更多,但每一步都清清楚楚,就像在讲一个故事。

递归CTE:处理层级数据

CTE还有一个杀手级功能,那就是递归查询。在处理树形结构或者层级数据时,递归CTE简直是救命稻草。

什么是递归CTE?简单说就是一个CTE在定义时引用了自己。这听起来有点绕,但实际上很有用。比如你有一个员工表,每个员工都有一个经理ID,你想要查询整个公司的组织架构,从CEO开始一层一层往下,这时候递归CTE就派上用场了。

递归CTE的语法是这样的:

WITH RECURSIVE cte_name AS (
-- 基础查询(锚点成员)
SELECT ...
WHERE base_condition
UNION ALL
-- 递归查询(递归成员)
SELECT ...
FROM cte_name
WHERE recursive_condition
)
SELECT * FROM cte_name;

让我们看一个实际例子。假设有这样的员工表:

CREATE TABLE Employees (
EmpID INT PRIMARY KEY,
Name VARCHAR(50),
ManagerID INT
);
INSERT INTO Employees VALUES
(1, 'Nia', NULL),      -- CEO,没有经理
(2, 'Omar', 1),        -- 向Nia汇报
(3, 'Priya', 1),       -- 向Nia汇报
(4, 'Quinn', 2),       -- 向Omar汇报
(5, 'Rui', 2);         -- 向Omar汇报

现在我们想要查询整个管理层级,标记每个员工在第几层:

WITH RECURSIVE ManagementHierarchy AS (
-- 基础情况:找到最顶层的管理者(没有经理的人)
SELECT
EmpID,
Name,
ManagerID,
0 AS Level
FROM Employees
WHERE ManagerID IS NULL
UNION ALL
-- 递归情况:找到下一层的员工
SELECT
e.EmpID,
e.Name,
e.ManagerID,
mh.Level + 1
FROM Employees e
JOIN ManagementHierarchy mh ON e.ManagerID = mh.EmpID
)
SELECT
EmpID,
Name,
Level,
CASE
WHEN Level = 0 THEN 'CEO'
WHEN Level = 1 THEN 'Manager'
ELSE 'Employee'
END AS Position
FROM ManagementHierarchy
ORDER BY Level, EmpID;

这个查询是怎么工作的呢?

首先执行基础查询,找到ManagerID为NULL的员工,也就是Nia,她的Level是0。

然后开始递归。第一次递归,从Employees表中找那些ManagerID等于Nia的EmpID的员工,也就是Omar和Priya,他们的Level是0+1=1。

第二次递归,找那些经理是Omar或Priya的员工,也就是Quinn和Rui,他们的Level是1+1=2。

第三次递归,没有找到任何员工的经理是Quinn或Rui,递归结束。

最后把所有层级的结果用UNION ALL合并起来,就得到了完整的组织架构:

EmpID | Name  | Level | Position
------|-------|-------|----------
1     | Nia   | 0     | CEO
2     | Omar  | 1     | Manager
3     | Priya | 1     | Manager
4     | Quinn | 2     | Employee
5     | Rui   | 2     | Employee

递归CTE在处理这种层级数据时真的非常优雅。如果不用递归,你可能需要写多次自连接,而且只能查询固定的层数。用递归CTE,无论你的组织架构有多少层,一个查询就搞定了。

CTE vs 子查询 vs 视图:该用哪个?

到这里你可能会问:既然子查询也能完成同样的功能,我什么时候该用CTE,什么时候该用子查询呢?还有,CTE和视图(VIEW)又有什么区别?

让我给你一些实用的建议:

当你的查询逻辑比较复杂,需要多个步骤来完成,用CTE。CTE能让你的代码结构清晰,就像写程序时把复杂功能拆分成多个函数一样。

当你需要在一个查询中多次引用同一个子查询结果,用CTE。虽然用子查询也能做到,但你需要把子查询重复写多次,而CTE定义一次就可以多次使用。

当你的查询逻辑很简单,就是一个简单的过滤或者存在性检查,用子查询就够了。比如WHERE id IN (SELECT ...)或者WHERE EXISTS (SELECT ...),这种情况下用CTE反而显得小题大做。

当你需要在多个查询中重复使用同一段逻辑,或者需要给不同的用户提供不同的数据视图,用VIEW。VIEW是持久化的数据库对象,可以跨查询、跨会话使用,而CTE只在当前查询中存在。

从性能的角度来说,现代数据库的查询优化器通常会把CTE和等价的子查询优化成相同的执行计划。所以大多数情况下,性能不应该是你选择CTE还是子查询的主要考虑因素。更重要的是代码的可读性和可维护性。

实用技巧和注意事项

在实际使用CTE时,有一些小技巧可以让你的SQL写得更好。

第一个技巧是给CTE起一个有意义的名字。不要用cte1cte2这种没有意义的名字,而要用customer_totalspayment_summary这种一看就知道在做什么的名字。好的命名本身就是最好的注释。

第二个技巧是合理控制CTE的数量。虽然CTE能让代码更清晰,但如果一个查询定义了十几个CTE,反而会让人眼花缭乱。一般来说,三到五个CTE是比较合适的。如果你发现需要更多的CTE,可能需要考虑是不是可以简化业务逻辑,或者把某些步骤做成视图。

第三个技巧是利用CTE来调试复杂查询。当你写一个复杂查询遇到问题时,可以先单独运行每个CTE,检查中间结果是否正确。这比在一个大的嵌套查询中找问题要容易得多。

还有一个需要注意的地方是递归CTE的终止条件。递归查询如果写得不好,可能会陷入无限循环。大多数数据库都有最大递归深度的限制来防止这种情况,但你还是应该确保递归条件最终会变为假。

关于性能,虽然我前面说了CTE和子查询通常性能相当,但在某些特殊情况下还是有区别的。如果你的CTE被多次引用,某些数据库可能会物化(materialize)这个CTE,也就是把结果存储在临时表中。这可能是好事(避免重复计算),也可能是坏事(占用内存)。如果你关心性能,应该用EXPLAIN命令查看实际的执行计划。

总结

CTE是SQL中一个非常强大的功能,它能让复杂的查询变得清晰易懂。通过把复杂的逻辑分解成多个有名字的步骤,CTE让你的SQL代码更像是在讲一个故事,而不是一堆难以理解的嵌套查询。

在我们的实战案例中,你看到了CTE如何处理订单支付分析、课程先修课程检查、组织架构查询等各种实际业务场景。对比子查询方案,CTE的优势在于可读性和可维护性,虽然在简单场景下子查询也足够用。

递归CTE更是处理层级数据的神器,让原本需要多次自连接或者存储过程才能完成的任务变得简单直接。

掌握CTE不仅能提升你的SQL技能,更重要的是它能改变你思考问题的方式。下次当你面对一个复杂的数据查询需求时,不妨试着用CTE把问题分解成几个清晰的步骤,你会发现很多看似困难的问题其实都可以迎刃而解。

记住,好的SQL代码不仅要能正确运行,还要让其他人(包括三个月后的你自己)能够轻松理解。而CTE正是实现这个目标的最佳工具之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/948974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 安全审计日志保留与定期备份整改操作文档

MySQL 日志定期备份与保留整改操作文档 一、整改背景 等保测评发现项:问题描述: MySQL 数据库日志保留不满足 180 天,未定期进行备份。 控制要求: 应对审计记录进行保护,定期备份,避免受到未预期的删除、修改或覆…

Alibaba Cloud Linux 3 +Docker 部署 ThinkPHP6 (宝塔环境)-问题篇 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

MES 文摘

活到老,学到老。

从网页到桌面:自定义URL协议让应用无缝衔接

从网页到桌面:自定义URL协议让应用无缝衔接技术的世界里,协议如同世界的语言,掌握它便能打通无数可能在浏览网页时,点击一个链接就能启动电脑上的本地应用程序,这种神奇的体验背后隐藏着怎样的技术原理?本文将从…

2025 年西宁靠谱旅行社,青海出国游报团旅行社,青甘环线旅行社最新推荐,聚焦资质、案例、售后的五家旅行社深度解读

引言 为助力消费者精准筛选 2025 年西宁靠谱旅行社、青海出国游报团旅行社及青甘环线旅行社,青海省旅游协会联合国内知名旅游测评机构,开展了为期 3 个月的权威测评。本次测评采用 “三维九项” 评估体系,从资质合规…

Oracle案例:tar安装数据库并从10.2.0.4.8升级到10.2.0.4.9

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。Oracle案例:…

2025 年西北环线旅行社,青海口碑最好的旅行社,青甘大环线旅行社最新推荐,聚焦资质、案例、售后的五家旅行社深度解读

引言 随着西北环线、青甘大环线旅游热度持续攀升,选择靠谱旅行社成为游客出行关键。为给游客提供权威参考,旅游协会联合地方旅游行业协会开展 2025 年相关旅行社测评工作。测评从资质合规性、服务案例质量、售后保障…

读书笔记:Oracle分区黑科技:间隔引用分区与虚拟列分区详解

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本文为个人学…

2025 年青海旅行社,青海性价比高的旅行社,西宁旅行社最新推荐,聚焦资质、案例、售后的五家旅行社深度解读

引言 为助力消费者精准挑选 2025 年青海及西宁地区高性价比旅行社,青海省旅游协会联合第三方专业测评机构开展权威测评。本次测评从资质合规性、服务案例满意度、售后保障体系三大核心维度入手,对青海省内 50 余家旅…

2025年在线折光浓度仪厂家权威推荐榜单:在线折光计/在线近红外光谱仪/在线折光率仪源头厂家精选

在工业过程控制与智能制造快速发展的背景下,在线折光浓度仪作为关键的流程分析设备,正以其高精度、实时性的测量优势成为多个行业的标配装备。 据流程工业仪器仪表市场报告显示,2024年全球在线浓度仪市场规模达到42…

第五届电子通信与计算机科学技术国际学术会议(ECCST 2025)

第五届电子通信与计算机科学技术国际学术会议(ECCST 2025) 2025 5th International Conference on Electronic Communication,Computer Science and Technology 在这里看会议官网详情 会议时间:2025年12月26-28日 会…

2025 年方形无缝钢管,无缝钢管圆改方,镀锌无缝钢管厂家最新推荐,产能、专利、环保三维数据透视

引言 方形无缝钢管、无缝钢管圆改方及镀锌无缝钢管在建筑结构、机械制造、流体输送等领域应用日益广泛,但市场产品质量差异显著,部分产品存在镀锌层脱落、方管角度偏差大、圆改方精度不足等问题,给采购决策带来困扰…

VSCode Debug 插件

首先得有这个插件1.创建一个 launch.json文件2.选择debugger类型

2025 年精密无缝钢管、合金无缝钢管、高压锅炉无缝钢管厂家最新推荐,精准检测与稳定性能深度解析

引言 精密、合金及高压锅炉用无缝钢管作为高端制造与能源领域的核心耗材,其质量直接关系到设备运行安全与工程可靠性。为破解市场选型难题,本次推荐基于第三方检测机构(具备 CMA/CNAS 双重认证)的权威数据,结合行…

2025年分子动力学仿真厂家权威推荐榜单:动力学模拟/分子动力学模拟/粗粒化模拟源头厂家精选

在科研与工业研发需求日益增长的今天,分子动力学模拟软件已成为化学物理、材料科学和生物物理学等领域不可或缺的工具。 根据QYR最新研究数据,2024年全球分子动力学软件市场规模已达数亿元人民币,预计到2031年将保持…

SQL改写:99%DBA估计都会忽略的重大知识点

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。今天在给一个…

NAS助手 — 纯血鸿蒙时代的 NAS 文件分享新方案

​ 🚀 NAS助手 — 纯血鸿蒙时代的 NAS 文件分享新方案​在当前阶段,官方尚未发布原生鸿蒙版本的 NAS 管理类应用,导致我们在日常使用中面临一些限制: 📁 无法直接将图片或视频批量上传至 NAS 🧾 办公文件传输…

2025年办公室玻璃隔断型材厂家权威推荐榜单:专业玻璃隔断/广州办公室隔断/双层玻璃百叶隔断源头厂家精选

随着现代办公环境不断升级,玻璃隔断市场需求持续增长。据行业统计数据显示,2024年全国办公室隔断市场规模突破280亿元,其中玻璃隔断占比达64%,年增长率稳定在15% 左右。广州作为粤港澳大湾区的核心城市,办公空间装…

Draco 编译及配置

1.下载Draco源码 地址:https://github.com/google/draco/tree/main 下载 Draco 1.5.7 release 或直接克隆 master 2.依赖环境 克隆源码后,打开third_party文件夹可看到其依赖的第三方库,下载源码:eigen(3.4.1) :…

第十一届中国大学生程序设计竞赛 女生专场

https://qoj.ac/contest/2564 一些题目挺经典