ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SQL Server常用函数实战清单:日期、字符串与聚合统计详解

2026/9/30 3:50:54 拓冰建站 浏览量
SQL Server常用函数实战清单:日期、字符串与聚合统计详解 聊到SQL Server绝大多数人最先想搞明白的就是日期转换、字符串处理、数学计算和聚合统计这四类常用函数。我做了这么多年数据相关的工作凡是写报表、做数据分析、维护数据库后台翻来覆去用的也就是这些功能。这篇就把SQL Server里最常用的函数整理成一份能直接抄作业的清单每个函数都配上说明和示例遇到日期转字符串、字符串转数字、分组汇总这类需求直接照着写就行。不管是刚接触SQL的新手还是已经写了几年存储过程的开发这份内容都能让你少走弯路。我会把那些容易被忽略的细节、经常踩的坑一块讲清楚比如LEN到底计不计空格、COUNT(*)和COUNT(列)差在哪、ROUND的第三个参数是干嘛的、GROUP BY和HAVING的执行顺序等等。看的时候建议顺手开个SQL Server Management StudioSSMS跟着敲一遍记忆会扎实很多。1. 先弄明白这些函数到底解决什么问题1.1 这些函数在真实项目里长什么样很多人学函数是一股脑背语法背完就忘。实际上SQL函数不是靠背的是靠需求驱动记住的。你真正写报表的时候会遇到的问题无非这么几类订单时间要转成2024-05-01这种格式、客户姓名要去掉首尾空格、价格要向上取整、各部门销售总额要汇总对比、某个月的销售额环比增长率要算出来。我举个例子一张订单表Orders有订单日期OrderDate、客户ID CustomerID、金额Amount。最常见的统计需求就是2024年每个月每个部门的销售总额、订单数、平均客单价。拆开看它就是组合使用CONVERT把OrderDate转成月份标识SUM、COUNT、AVG做聚合GROUP BY按部门和月份分组DATEDIFF或DATEPART算时间维度。这些函数单独看都不难难的是组合能力和对细节的把控。所以这篇不只是列函数清单更会解释每个函数背后的行为和容易出错的地方。明白这些你遇到问题的时候才会知道该用哪个、为什么用这个、用了之后可能踩什么坑。1.2 我建议的学法和查法学习SQL Server函数最忌讳的就是拿起一本书从头念到尾。我的经验是先建一个临时表塞入几行测试数据把每个函数跑一遍再看结果是否符合预期。比如建一个只有几行的订单表分别验证SUM、AVG、COUNT、字符串拼接、日期加减效果比看一百遍语法都好。另外把常用函数整理成一张速查表放到手边。这篇内容你完全可以当成速查手册用看到某个函数想不起来具体语法直接搜标题或者关键词就能定位。我平时写SQL也是查得多了才有肌肉记忆别指望一次记住所有东西。2. 日期转换与日期时间函数格式化、加减、区间计算2.1 先拿当前日期GETDATE 和 SYSDATETIME做报表几乎每次都要取当前时间。SQL Server里最基本的两个函数是GETDATE()和SYSDATETIME()。SELECT GETDATE(); -- 返回当前日期和时间精度到毫秒 SELECT SYSDATETIME(); -- 返回当前日期和时间精度到100纳秒如果只是需要当前日期不要时间可以用SELECT CAST(GETDATE() AS DATE);注意CAST需要写完整它的作用是去掉时间部分只保留年月日。这在报表日期条件里非常常用比如查今天所有的订单SELECT * FROM Orders WHERE OrderDate CAST(GETDATE() AS DATE);这个写法比拿OrderDate和GETDATE()直接比较要可靠因为它不会漏掉当天的记录。2.2 日期转字符串CONVERT 样式号别硬背SQL Server把日期转字符串最常用的不是CAST而是CONVERT。CONVERT的语法是 CONVERT(目标类型, 表达式, 样式号)。这里样式号就是很多人记不住的地方其实只用记常用的几个就够了。SELECT CONVERT(varchar(10), GETDATE(), 101); -- MM/dd/yyyy SELECT CONVERT(varchar(10), GETDATE(), 103); -- dd/MM/yyyy SELECT CONVERT(varchar(10), GETDATE(), 112); -- yyyyMMdd SELECT CONVERT(varchar(23), GETDATE(), 120); -- yyyy-MM-dd HH:mm:ss SELECT CONVERT(varchar(23), GETDATE(), 121); -- yyyy-MM-dd HH:mm:ss.mmm SELECT CONVERT(varchar(10), GETDATE(), 23); -- yyyy-MM-dd日常工作中112和120是我用得最多的。112适合做排序因为年月日数值大小就代表日期的先后120适合导出给别的系统中间有横杠和冒号别人一眼能看懂。101和103的区别要特别注意101是月在前美国习惯103是日在先欧洲习惯如果不小心把用户传过来的日期当成另一种格式解析非常容易出错。还有个常见需求是日期转成中文格式SQL Server没有直接的yyyy年MM月dd日内置样式但可以用CONVERT加字符串拼接实现SELECT CONVERT(varchar(4), DATEPART(year, GETDATE())) 年 CONVERT(varchar(2), DATEPART(month, GETDATE())) 月 CONVERT(varchar(2), DATEPART(day, GETDATE())) 日;这种写法在生成中文报表标题时很常见。2.3 字符串转日期三种写法与坑把字符串转成日期有的朋友一上来就写CAST(2024-05-01 AS DATE)大多数情况没问题可一旦遇到20240501这种格式CAST直接报错或者返回奇怪的结果。稳妥的做法是用CONVERT并指定样式号。-- 推荐写法 SELECT CONVERT(DATE, 20240501, 112); SELECT CONVERT(DATETIME, 2024-05-01 12:30:00, 120); -- 不推荐但常见的写法 SELECT CAST(2024-05-01 AS DATE);如果文本来源不可控混进了abc之类的内容SQL Server 2012以后可以用TRY_CONVERT和TRY_CAST。它们转换失败时不会报错而是返回NULL让程序走下一步处理SELECT TRY_CONVERT(DATE, 2024-13-01, 112); -- 返回NULL因为13月不合法 SELECT TRY_CAST(abc AS INT); -- 返回NULL这个特性在写批量导入和清洗脏数据时非常好用能保住整个查询不被一条坏数据拖垮。2.4 DATEADD、DATEDIFF、DATEPART日期加减和区间计算DATEADD用于给日期加时间单位DATEDIFF用于计算两个日期的间隔DATEPART用于取日期的某一部分年、月、日、周几等。三个都是高频函数但各有各的细节坑。-- 加7天、减3个月 SELECT DATEADD(day, 7, GETDATE()); SELECT DATEADD(month, -3, GETDATE()); -- 两个日期相差多少天 SELECT DATEDIFF(day, 20240101, 20240110); -- 9 -- 取当前日期的年份、月份 SELECT DATEPART(year, GETDATE()); SELECT DATEPART(month, GETDATE());DATEDIFF有个特别容易踩的坑它计算的是两个日期之间边界跨越的次数不是精确的时间间隔。比如DATEDIFF(year, 20231231, 20240101)返回1因为年份边界从2023跨到了2024但两个日期实际只差一天。如果你要计算精确的相差天数、小时数通常没问题但跨年、跨月、跨周的统计一定要想清楚需求。另外DATEPART(weekday, GETDATE())返回的是1到7但数字代表星期几跟当前会话的DATEFIRST设置有关。默认情况下SQL Server认为周日是1如果想按周一作为一周的开始先执行SET DATEFIRST 1;否则你在统计周一订单量时很容易把周日也算进去。再说一个经典写法求本月第一天。大多数人的第一反应是拼字符串其实有更优雅的写法SELECT DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0);这个式子的原理是0代表基准日期1900-01-01先把当前日期和基准日期之间跨越的月数算出来再把这么多个“整月”加回基准日期得到的一定是本月1号。同理求上月末可以先用EOMONTH函数SELECT EOMONTH(GETDATE()); -- 本月最后一天 SELECT DATEADD(day, 1, EOMONTH(GETDATE())); -- 下月第一天EOMONTH是SQL Server 2012加入的函数做月末统计时比手工算日期方便太多。2.5 FORMAT 更灵活但慢SQL Server 2012以后有个FORMAT函数可以直接用.NET的格式写法转日期SELECT FORMAT(GETDATE(), yyyy-MM-dd); SELECT FORMAT(GETDATE(), yyyy年MM月dd日);FORMAT在灵活性上确实很好但性能比CONVERT差不少。因为它底层要调用.NET的CLR方法每行数据都要做一次格式化。如果只是对单条数据做格式化没关系但用在百万行的大表查询里速度差距会很明显。我的习惯是导出少量数据或者做界面展示时用FORMAT大数据量加工时一律用CONVERT。另外FORMAT的格式串区分大小写月份用大写MM分钟用小写mm年份用yyyy小写。写错了不会报错但可能输出一串莫名其妙的原文排查起来非常费劲。3. 字符串函数截取、拼接、替换、拆分全套实操3.1 长度与截取LEN、LEFT、RIGHT、SUBSTRING字符串处理里最常用的就是取长度和截取。SELECT LEN(Hello World); -- 11 SELECT LEFT(Hello World, 5); -- Hello SELECT RIGHT(Hello World, 5); -- World SELECT SUBSTRING(Hello World, 7, 5); -- World从第7个字符开始取5个这里有个折磨过不少人的细节LEN不计尾随空格DATALENGTH才计实际字节数。SELECT LEN(abc ); -- 3 SELECT DATALENGTH(abc ); -- 5更要注意的是列类型是NVARCHAR时DATALENGTH会按每个字符2字节计算这跟VARCHAR1字符1字节不一样。如果你用DATALENGTH判断字符串长度中文字符和NVARCHAR类型会让你莫名其妙多出一倍。所以判断字符数用LEN判断存储空间用DATALENGTH别混用。截取函数有个使用细节SUBSTRING的起始位置和长度都是基于字符位置不是字节位置。中文字符按一个字符算这部分没问题。但如果你要截取一段可能包含中文的字符串请确保使用NVARCHAR而不是VARCHAR否则中文可能变成问号或截断。3.2 查找与替换CHARINDEX、PATINDEX、REPLACE、STUFFCHARINDEX用来找子串位置PATINDEX则支持通配符模式匹配。REPLACE用来替换STUFF则能实现删除指定位置长度的字符串再插入新内容。SELECT CHARINDEX(bc, abcd); -- 2找不到返回0 SELECT PATINDEX(%[0-9]%, abc123); -- 4第一次出现数字的位置 SELECT REPLACE(abcabc, bc, XY); -- aXYaXY SELECT STUFF(abcdef, 2, 3, XY); -- aXYefCHARINDEX和PATINDEX这对组合我很常用。比如处理地址栏信息时要看某列里是否包含手机号或者特定关键词就用它们做判断条件。STUFF是个容易被忽略但非常实用的函数。它比SUBSTRING加字符串拼接灵活得多。一个典型场景是脱敏把身份证号中间几位替换成星号。SELECT STUFF(110101199001011234, 7, 8, ********); -- 结果110101********1234REPLACE在清理脏数据时威力巨大。比如用户录入电话号码时混入了空格、横线可以一次性用嵌套REPLACE去掉SELECT REPLACE(REPLACE(REPLACE(010-1234 5678, -, ), , ), , );不过要注意REPLACE是全局替换不是只替换第一次出现的子串。如果你的需求是只换第一个REPLACE做不到得配合STUFF和CHARINDEX来定位。3.3 拼接与清洗CONCAT、加号、LTRIM/RTRIM/UPPER/LOWER字符串拼接是另一个高频场景。SQL Server里有两种拼接方式加号运算符和CONCAT函数。这两者的区别非常大尤其是遇到NULL的时候。SELECT a b; -- ab SELECT a NULL; -- NULL灾难 SELECT CONCAT(a, NULL, b); -- abCONCAT会跳过NULL这个坑我踩过太多次。做报表拼接地址、姓名时如果某个字段为NULL用加号拼接出来的结果整个变成NULL排查半天才发现是某个地址段为空。所以只要存在空值风险优先用CONCAT。如果用的是旧版本SQL Server2012之前没有CONCAT函数那就得用ISNULL或COALESCE先兜底再拼接。清洗字符串同样常用。LTRIM去掉左侧空格RTRIM去掉右侧空格SQL Server 2017以后可以直接用TRIM同时去掉两侧空格。注意它们默认只处理普通空格换行符、制表符不在处理范围。如果想同时清理缩进可以配合REPLACE把CHAR(9)、CHAR(10)替换掉。大小写转换UPPER和LOWER在处理用户输入标准化时有用比如用户名不区分大小写、身份证号里的字母统一转大写。不过提到大小写SQL Server本身的排序规则决定了字符串比较时候是否区分大小写。如果数据库排序规则不区分大小写那么WHERE Name abc也能匹配ABC。需要严格匹配大小写时可以用COLLATE指定排序规则。3.4 SQL Server 2016 拆分与聚合STRING_SPLIT 与 STRING_AGGSQL Server 2016开始有STRING_SPLIT2017开始有STRING_AGG这俩是处理字符串与行集互转的神器。SELECT value FROM STRING_SPLIT(apple,banana,orange, ,);结果返回三行。这个函数用来处理逗号分隔的ID列表非常方便可以直接JOIN到业务表上。但有两个点要注意一是STRING_SPLIT不保证输出顺序也就是说你无法依赖它按原字符串顺序返回行二是它直接返回的结果集列名是value如果你想换成其他列名需要加别名。STRING_AGG则是把多行字符串聚合成一行类似MySQL的GROUP_CONCAT。SELECT dept, STRING_AGG(emp_name, ,) AS employees FROM employee GROUP BY dept;如果希望拼接结果有序可以用WITHIN GROUPSELECT dept, STRING_AGG(emp_name, ,) WITHIN GROUP (ORDER BY emp_name) FROM employee GROUP BY dept;这个语法写起来有点长但效果很好。STRING_AGG同样会自动忽略NULL值不会把NULL拼进结果里。如果你要拼接的是去重后的值目前不能直接在STRING_AGG里写DISTINCT需要先子查询去重再聚合。4. 数学函数与聚合函数从单行计算到分组统计4.1 必须掌握的数学函数纯数学函数平时用得不那么频繁但只要是做金额、价格、数量相关的计算总会碰到几个。SELECT ABS(-100); -- 100 SELECT CEILING(3.2); -- 4向上取整 SELECT FLOOR(3.8); -- 3向下取整 SELECT ROUND(123.456, 2); -- 123.46四舍五入保留两位 SELECT ROUND(123.456, 2, 1); -- 123.45第三个参数非0表示直接截断 SELECT POWER(2, 10); -- 1024 SELECT SQRT(16); -- 4 SELECT FLOOR(RAND() * 10) 1; -- 1到10的随机整数ROUND的第三个参数是我见过很多人不知道的小细节。默认不传第三参就是四舍五入传了非0值就变成截断也就是不四舍五入后面的数字直接扔掉。这在金融计算里偶尔会遇到比如有些客户要求分以下直接舍掉这时ROUND(value, 2, 1)比转字符串再截取靠谱得多。RAND返回0到1之间的随机小数不能直接当随机整数用要用它配合FLOOR或CAST转换。ORDER BY NEWID()也可以实现随机排序从结果集里随机抽N条记录SELECT TOP 5 * FROM Orders ORDER BY NEWID();这个方法在抽样、随机派单、随机出题场景里都很好用但注意大表上做随机排序会有性能开销。还有一个数学计算里的经典坑整数除法。SQL Server里两个整数相除结果还是整数小数部分直接截掉。SELECT 5 / 2; -- 2不是2.5 SELECT 5 / 2.0; -- 2.5 SELECT CAST(5 AS DECIMAL(10,2)) / 2; -- 2.50我见过太多报表里因为忘了加.0导致平均单价、占比算出来全是整数。比如SUM(amount) / COUNT(*) 这种组合如果两个操作数都是INT类型结果就是整数。写平均数、百分比的时候一定要先把分子或分母转成小数类型。4.2 聚合函数的底层逻辑COUNT、SUM、AVG、MAX、MIN聚合函数是分组统计的核心。大多数人会用但对NULL的处理规则未必清楚。下面这个规律是理解聚合函数的关键除了COUNT(*)之外SUM、AVG、COUNT(列)、MAX、MIN都会忽略NULL值。SELECT SUM(Amount) FROM Orders; SELECT AVG(Amount) FROM Orders; SELECT COUNT(*) FROM Orders; -- 所有行数 SELECT COUNT(Amount) FROM Orders; -- Amount不为NULL的行数 SELECT COUNT(DISTINCT CustomerID) FROM Orders; -- 去重客户数 SELECT MAX(OrderDate), MIN(OrderDate) FROM Orders;COUNT()和COUNT(列)的区别经常被忽略。假设某张表的折扣率列有很多NULLCOUNT()返回总行数COUNT(DiscountRate)只返回非NULL的折扣率记录数。写报表标题有效折扣记录数时这个区别直接决定了数字对不对。MAX和MIN不只是数字使用字符串也可以比大小按排序规则来取最大最小日期当然也可以而且取最大日期就是最新日期。这在业务里很常见比如每个客户最近一次下单时间SELECT CustomerID, MAX(OrderDate) AS LastOrderDate FROM Orders GROUP BY CustomerID;还有一个容易踩的NULL陷阱SUM和AVG在没有可汇总的行时返回NULL不是0。比如某个部门没有任何符合条件的订单SUM(Amount)就是NULL。如果报表里直接展示会出现一个空白的数字甚至导致后续计算全变NULL。处理方法是提前用ISNULL或COALESCE兜底SELECT dept, ISNULL(SUM(Amount), 0) AS TotalAmount FROM Orders GROUP BY dept;4.3 GROUP BY 与 HAVING先过滤还是后过滤聚合函数配合GROUP BY分组基本是报表开发的家常便饭。但很多人写分组查询时没有意识到WHERE和HAVING的执行顺序。SELECT dept, COUNT(*) AS OrderCount, SUM(Amount) AS TotalAmount FROM Orders WHERE Status success GROUP BY dept HAVING COUNT(*) 10;执行顺序是这样的先通过WHERE过滤行再进行分组聚合最后用HAVING过滤分组结果。所以WHERE后面不能写聚合函数比如WHERE COUNT(*) 10会直接报错而HAVING后面也不能写原始列条件比如HAVING Status success虽然不报错但逻辑不对。性能上如果能在WHERE里把数据过滤掉尽量用WHERE因为分组的数据越少整个查询越快。HAVING只在过滤聚合结果这种WHERE做不到的场景才用。这种写法上的区分不光是正确性问题也会影响大表查询的速度。另外还要提一个常见错误GROUP BY的select列表中只能出现分组列或者聚合函数。有的开发习惯不好在MySQL里能跑通的写法到了SQL Server直接报错-- 错误示例Name没有出现在GROUP BY中 SELECT dept, Name, COUNT(*) FROM employee GROUP BY dept;这不是SQL Server限制得太死而是这种查询的结果本身就不明确。正确做法是明确分组维度或者用MAX、MIN等聚合函数把剩余列都包进去。4.4 进阶聚合ROLLUP、CUBE、GROUPING SETS 和窗口函数如果只是按一个维度分组GROUP BY就够用了。但报表经常需要部门小计、总计这种多级汇总这时候ROLLUP和GROUPING SETS就派上用场了。SELECT dept, duty, SUM(salary) AS TotalSalary FROM employee GROUP BY ROLLUP(dept, duty);这个查询会返回正常分组行、部门小计行和总计行。小计和总计行里没有参与汇总的列会显示NULL。为了区分正常的NULL值和汇总产生的NULL可以用GROUPING函数SELECT CASE WHEN GROUPING(dept) 1 THEN ALL ELSE dept END AS dept, CASE WHEN GROUPING(duty) 1 THEN ALL ELSE duty END AS duty, SUM(salary) AS TotalSalary FROM employee GROUP BY GROUPING SETS ((dept, duty), (dept), ());GROUPING SETS比ROLLUP更灵活可以自定义需要哪几层小计。这个写法在生成动态汇总报表时非常实用虽然初看起来有点复杂但一旦掌握能省掉来回拼接多条SQL的麻烦。还有一类和聚合强相关的功能是窗口函数简单说就是分组聚合但不合并行。比如想要每个员工及其所在部门的工资总额SELECT emp_name, dept, salary, SUM(salary) OVER(PARTITION BY dept) AS dept_total FROM employee;每个员工行都会保留同时后面多一列部门合计。这在计算占比、排名、同比环比时非常好用。窗口函数不算是严格的聚合函数但它和聚合函数配合能解决很多复杂问题。遇到既要明细又要汇总的需求时优先考虑OVER。5. 常见问题与排查技巧实录5.1 日期转换最容易踩的4个坑第一个坑样式号记混。101是MM/dd/yyyy103是dd/MM/yyyy120是yyyy-MM-dd HH:mm:ss112是yyyyMMdd。搞混之后日期不会报错但数据含义完全变了比如把3月5日变成5月3日。建议在代码里统一约定格式不然后期排查非常痛苦。第二个坑依赖字符串隐式转换。把2024/05/01、2024.05.01、20240501这些格式直接CAST成日期结果跟当前数据库的语言设置强相关。最可靠的做法是显式加上样式号比如CONVERT(DATE, 20240501, 112)这样无论谁在什么环境里跑结果都一致。第三个坑DATEDIFF边界问题。前面提到过DATEDIFF算的是边界跨越次数。统计年龄、工龄、周岁时如果你要的是满多少年直接DATEDIFF(year, birth, GETDATE())会把人算大一岁因为只要跨了元旦就加1。这种需求通常要用DATEADD构造出精确的生日判断再计算。第四个坑FORMAT性能。FORMAT虽然方便但它是逐行调用CLR。大数据量分组格式化时可能比CONVERT慢几十倍。能用样式号解决的就别用FORMAT去格式化每一行。5.2 函数套在列上导致索引失效这也是一个容易忽略的问题。假设表里OrderDate列有索引下面的查询会让SQL Server放弃索引SELECT * FROM Orders WHERE YEAR(OrderDate) 2024;因为每一行都要先算出YEAR(OrderDate)才能和2024比较索引排序根本帮不上忙。改写为范围查询就能利用索引SELECT * FROM Orders WHERE OrderDate 20240101 AND OrderDate 20250101;这不仅仅影响执行速度在数据量大的表上差的可能是几十倍。养成习惯查询条件里尽量不套函数改成对列本身的区间判断。5.3 聚合结果为空和NULL的处理前面说过SUM在没有匹配行时返回NULL。实际业务中报表模板往往期望显示0而不是空白。推荐统一用ISNULL包裹聚合结果SELECT dept, ISNULL(SUM(Amount), 0) AS TotalAmount, ISNULL(AVG(Amount), 0) AS AvgAmount FROM Orders GROUP BY dept;同样如果想让AVG把NULL值当作0参与平均直接AVG(ISNULL(Amount, 0))。要清楚这跟AVG默认行为忽略NULL的差异别搞混。5.4 连接不上SQL Server含第三方软件连接案例搜热词时看到不少人遇到某个软件无法连接到SQL Server比如SolidWorks Electrical配置连接时提示连不上。这种问题通常不是函数问题而是连接层面的问题。排查顺序一般是确认SQL Server服务是否启动。打开SQL Server配置管理器看SQL Server服务状态是否为正在运行。确认实例名和端口。默认实例通常是计算机名命名实例是计算机名\实例名。端口默认1433但命名实例可能是动态端口。确认TCP/IP协议是否启用。配置管理器里SQL Server网络配置下把TCP/IP设为已启用并重启服务。确认防火墙是否放行1433端口。确认身份验证模式。如果是SQL Server身份验证安装时选了Windows身份验证模式的话需要改成混合模式并设置好sa密码。如果SSMS本身能连上、第三方软件连不上那多半是第三方配置里的服务器名、端口或权限不对。用别名或者本机IP代替计算机名也是常见解决办法。5.5 SQL Server进程内存占用过高很多人看到服务器上sqlservr.exe占了大量内存就慌其实SQL Server的默认行为就是尽量吃掉可用内存做缓存这是设计如此。如果你要限制它不要影响操作系统和其他应用可以设置最大服务器内存EXEC sp_configure max server memory (MB), 8192; RECONFIGURE;也可以在SSMS右键服务器选择属性-内存设置最大服务器内存。设置完后SQL Server会自动调整不需要重启。这个操作在SQL Server和Windows Server共存的机器上非常有必要否则很容易出现系统内存告急。5.6 转换失败和参数化查询把字符串转数字失败是新手常见报错将varchar转换为数据类型int时失败。原因往往是数据里混入了空格、中文或字母。除了用TRY_CONVERT兜底更重要的习惯是任何用户输入都不应该用拼字符串的方式写进SQL。比如-- 非常糟糕的写法 SELECT * FROM Users WHERE UserName 张三 input;这种做法会因为引号转义问题导致错误还可能带来注入风险。正确做法是参数化查询无论是存储过程还是应用程序里都用参数传递输入值。SQL Server执行参数化查询时不会把输入当作SQL代码解析转换也交给引擎统一处理这才是最根本的解决方案。最后再聊几句我的个人使用习惯函数这东西光看不用很快就会忘。我自己的习惯是每接触一个新的SQL Server环境第一件事是确认版本然后建一张简单的测试表把日期转换、字符串拆分、聚合分组这些常用操作都跑一遍确认行为和自己预期一致。尤其在上了新版本SQL Server后我会专门试一下STRING_SPLIT、STRING_AGG、TRIM这些新函数看看能不能替代以前手工拼接的写法。给刚开始学SQL Server的朋友一个建议不要试图一次性把所有函数记住你现在只需要记住SQL Server有这些能力遇到问题时知道往哪个方向查。真正遇到具体需求时你自然会去搜语法、看示例用过几次就记住了。但有几个坑一定要提前知道——LEN不计尾随空格、COUNT(列)不等于COUNT(*)、ROUND第三参数是截断开关、SUM对空集返回NULL而不是0。这些坑在真实项目里一旦踩中排查起来极其浪费时间。如果你平时工作里经常写报表或者要处理各种历史数据建议把这些函数例子都自己敲一遍花不了多长时间但之后写SQL会顺很多。等用得多了你也会慢慢形成自己的一套速查清单到那时候这些函数就不再是知识点而是你解决问题的本能了。