作为一名长期与SQL Server打交道的数据库工程师,我深知函数库的熟练掌握对工作效率的提升有多重要。今天我将系统梳理SQL Server中最实用的字符串、日期、数学和聚合函数,这些都是在实际项目中反复验证过的核心工具集。
字符串处理是数据库开发中最常见的需求之一。SQL Server提供了丰富的字符串函数,我们先看几个基础但高频使用的:
sql复制-- 获取字符串长度
SELECT LEN('数据库') -- 返回3(注意:LEN函数对中文按字符计数)
-- 截取子字符串
SELECT SUBSTRING('SQLServer',4,6) -- 返回'Server'(从第4个字符开始取6个)
-- 去除首尾空格
SELECT TRIM(' hello ') -- 返回'hello'(新版SQL Server支持标准TRIM语法)
特别注意:在SQL Server 2016及以下版本中,TRIM函数需要使用LTRIM和RTRIM组合实现:
sql复制SELECT LTRIM(RTRIM(' text '))
实际项目中我们常需要处理更复杂的字符串场景:
sql复制-- 动态替换内容(支持正则表达式)
SELECT REPLACE('订单号:ORD123456', 'ORD', '') -- 返回'订单号:123456'
-- 字符串反转(可用于校验码生成)
SELECT REVERSE('ABCDE') -- 返回'EDCBA'
-- 格式化数字为字符串
SELECT STR(123.4567, 8, 2) -- 返回' 123.46'(总长度8,小数位2,自动四舍五入)
多字段拼接时NULL值会导致整个结果为NULL,这是新手常踩的坑:
sql复制-- 安全拼接方案
SELECT CONCAT('订单:', NULL, '123') -- 返回'订单123'(CONCAT自动忽略NULL)
SELECT '订单:' + ISNULL(NULL, '') + '123' -- 传统方案需要显式处理NULL
日期处理是业务系统的核心需求,以下是关键日期函数:
sql复制-- 获取当前日期(注意时区问题)
SELECT GETDATE() -- 返回服务器本地时间
SELECT SYSDATETIME() -- 更高精度的日期时间(纳秒级)
-- 提取日期部分
SELECT DATEPART(YEAR, GETDATE()) -- 返回2024(年份)
SELECT DAY('2024-03-15') -- 返回15(当月第几天)
业务中经常需要计算日期差或进行日期加减:
sql复制-- 计算两个日期差值
SELECT DATEDIFF(DAY, '2024-01-01', '2024-03-01') -- 返回60(间隔天数)
-- 日期加减
SELECT DATEADD(MONTH, 3, GETDATE()) -- 返回当前日期加3个月后的日期
-- 获取月末日期(财务系统常用)
SELECT EOMONTH(GETDATE()) -- 返回当月最后一天
不同地区对日期格式有不同要求:
sql复制-- 常用格式化样式
SELECT CONVERT(VARCHAR, GETDATE(), 120) -- '2024-03-15 14:30:00'
SELECT CONVERT(VARCHAR, GETDATE(), 112) -- '20240315'(适合作为文件名)
-- 自定义格式化(SQL Server 2012+)
SELECT FORMAT(GETDATE(), 'yyyy年MM月dd日') -- '2024年03月15日'
两种类型转换函数的区别与选择:
sql复制-- CAST是ANSI标准语法
SELECT CAST(123.456 AS INT) -- 返回123(直接截断小数)
-- CONVERT提供更多控制选项
SELECT CONVERT(INT, 123.456) -- 功能与CAST相同
SELECT CONVERT(VARCHAR, GETDATE(), 121) -- 可指定日期格式
经验法则:需要格式控制时用CONVERT,简单转换用CAST(保证代码可移植性)
SQL Server会自动进行某些类型转换,但可能产生意外结果:
sql复制-- 字符串与数字比较时的隐式转换
SELECT CASE WHEN '123' = 123 THEN '相等' ELSE '不等' END -- 返回'相等'
-- 但以下情况会失败
SELECT 'ABC' + 123 -- 报错:转换失败
sql复制-- 四舍五入的几种方式
SELECT ROUND(123.4567, 2) -- 123.4600(注意保留小数位数)
SELECT CAST(123.4567 AS DECIMAL(10,2)) -- 123.46(更精确的控制)
-- 随机数生成(适合抽样场景)
SELECT RAND(CHECKSUM(NEWID())) -- 生成真正的随机数(避免伪随机)
sql复制-- 财务计算常用
SELECT POWER(1.1, 5) -- 1.1的5次方(复利计算)
SELECT LOG(100, 10) -- 以10为底100的对数(返回2)
-- 统计计算辅助
SELECT SQRT(VAR(column)) -- 计算标准差
sql复制-- COUNT的三种用法
SELECT COUNT(*) -- 统计所有行数(包括NULL)
SELECT COUNT(column) -- 统计非NULL值
SELECT COUNT(DISTINCT column) -- 统计唯一值数量
-- 分组统计示例
SELECT
department_id,
AVG(salary) AS avg_salary,
STDEV(salary) AS salary_deviation
FROM employees
GROUP BY department_id
SQL Server 2012引入的强大功能:
sql复制-- 计算移动平均
SELECT
order_date,
amount,
AVG(amount) OVER (ORDER BY order_date ROWS 2 PRECEDING) AS moving_avg
FROM sales
-- 分组排名
SELECT
product_id,
sales_amount,
RANK() OVER (PARTITION BY category ORDER BY sales_amount DESC) AS rank_in_category
FROM products
字符串操作:避免在WHERE条件中对字段使用函数(会使索引失效)
sql复制-- 不推荐(索引失效)
SELECT * FROM orders WHERE YEAR(order_date) = 2024
-- 推荐写法
SELECT * FROM orders
WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01'
聚合查询:大数据量时考虑使用WITH ROLLUP/CUBE或GROUPING SETS
跨国项目必须考虑的时区问题:
sql复制-- 时区转换(SQL Server 2016+)
SELECT GETDATE() AT TIME ZONE 'China Standard Time'
SELECT GETDATE() AT TIME ZONE 'UTC'
-- 存储统一使用UTC时间
INSERT INTO events(event_time)
VALUES (GETUTCDATE())
IS NULL与= NULL的区别sql复制-- 组合日期与随机数生成唯一订单号
SELECT
CONCAT(
'ORD',
FORMAT(GETDATE(), 'yyyyMMdd'),
RIGHT(CAST(ABS(CHECKSUM(NEWID())) AS VARCHAR), 6)
) AS order_number
sql复制-- 清理并标准化电话号码
UPDATE customers
SET phone =
CASE
WHEN phone LIKE '+%' THEN phone -- 国际号码保留
ELSE CONCAT('+86', REPLACE(phone, '-', '')) -- 国内号码标准化
END
WHERE phone IS NOT NULL
sql复制-- 根据日期范围动态生成查询
DECLARE @start_date DATE = '2024-01-01'
DECLARE @end_date DATE = '2024-03-01'
DECLARE @sql NVARCHAR(MAX)
SET @sql = N'
SELECT
product_id,
SUM(quantity) AS total_quantity
FROM sales
WHERE sale_date BETWEEN ''' +
CONVERT(VARCHAR, @start_date, 23) + ''' AND ''' +
CONVERT(VARCHAR, @end_date, 23) + '''
GROUP BY product_id'
EXEC sp_executesql @sql
掌握这些核心函数后,90%的日常数据处理需求都能高效解决。建议在实际工作中建立自己的代码片段库,遇到复杂需求时先考虑能否用现有函数组合实现,这往往比自定义函数更高效可靠。