SQL 写法示例
按场景整理的 SQL 数据集写法:日期范围、可选条件、多选、分页、汇总、行级权限,附跨方言差异与常见错误。
概述
本文按任务给出可直接改用的 SQL 数据集写法,示例表为虚构的医院数据:
| 表 | 字段 |
|---|---|
outpatient_visit(门诊就诊) |
visit_id、patient_name、dept_code、doctor_account、visit_date、fee、status |
department(科室) |
dept_code、dept_name、parent_code |
orders(订单) |
order_no、customer_name、amount、status、create_time |
语法规则见 SQL 参数与动态语法。示例中的报表参数需先在报表参数中声明(用「从SQL提取参数到报表参数」自动登记,再调整类型)。
功能入口
在 SQL 数据集 的 SQL 编辑区粘贴示例,也可在编辑器的「常用写法」对话框中复制内置示例。
操作步骤
- 选择与任务最接近的示例,改表名与字段名。
- 点击「从SQL提取参数到报表参数」,为每个参数选择类型。
- 用「数据预览」填参数验证,在「SQL 预览」标签页确认最终 SQL 与参数。
示例
日期范围
参数 startDate、endDate 为日期类型,右端用「小于」,避免遗漏结束日当天的时间部分:
SELECT visit_id, dept_code, visit_date, fee
FROM outpatient_visit
WHERE visit_date >= $startDate
AND visit_date < $endDate
ORDER BY visit_date DESC
最近 N 天,参数 days:
SELECT order_no, amount, create_time
FROM orders
WHERE create_time >= ${addDays(now(), -$days)}
AND create_time < ${now()}
可选条件
参数 deptCode 可空,minFee 为数值可空:
SELECT visit_id, dept_code, fee
FROM outpatient_visit
WHERE 1 = 1
#{isEmpty($deptCode) ? '' : 'AND dept_code = $deptCode'}
#{$minFee != null ? 'AND fee >= $minFee' : ''}
多选科室
deptCodes 类型选「集合」:
SELECT visit_id, dept_code, fee
FROM outpatient_visit
WHERE dept_code IN (${$deptCodes})
关键词模糊查询
SELECT visit_id, patient_name, dept_code
FROM outpatient_visit
WHERE patient_name LIKE ${'%' + $kw + '%'}
分组汇总
SELECT dept_code,
COUNT(*) AS visit_cnt,
SUM(fee) AS total_fee
FROM outpatient_visit
WHERE visit_date >= $startDate AND visit_date < $endDate
GROUP BY dept_code
HAVING SUM(fee) > 0
ORDER BY total_fee DESC
关联科室名称
SELECT v.visit_id, v.patient_name, d.dept_name, v.fee
FROM outpatient_visit v
LEFT JOIN department d ON d.dept_code = v.dept_code
WHERE v.visit_date >= $startDate AND v.visit_date < $endDate
行级权限:只看自己接诊的数据
SELECT visit_id, patient_name, fee
FROM outpatient_visit
WHERE doctor_account = ${userAccount()}
管理员看全部(isAdmin 为布尔参数):
SELECT visit_id, patient_name, fee
FROM outpatient_visit
WHERE 1 = 1
#{$isAdmin == true ? '' : 'AND doctor_account = ${userAccount()}'}
引用系统自定义参数
「系统 > 自定义参数」中配置了 status,SQL 里要写成 ${$$config.status}:
SELECT order_no, amount, status
FROM orders
WHERE status = ${$$config.status}
手写分页
参数 pageNo(从 1 起)、pageSize。模板启用「数据浏览报表」时由系统分页,不要再手写。
| 数据库 | 写法 |
|---|---|
| MySQL、MariaDB、PostgreSQL | LIMIT $pageSize OFFSET ${($pageNo - 1) * $pageSize} |
| SQL Server | OFFSET ${($pageNo - 1) * $pageSize} ROWS FETCH NEXT $pageSize ROWS ONLY |
| Oracle | 三层嵌套,用 ROWNUM |
MySQL 完整示例:
SELECT order_no, amount, create_time
FROM orders
WHERE status = $status
ORDER BY create_time DESC
LIMIT $pageSize OFFSET ${($pageNo - 1) * $pageSize}
Oracle 完整示例:
SELECT *
FROM (
SELECT t.*, ROWNUM AS rn
FROM (
SELECT order_no, amount, create_time
FROM orders
WHERE status = $status
ORDER BY create_time DESC
) t
WHERE ROWNUM <= ${$pageNo * $pageSize}
)
WHERE rn > ${($pageNo - 1) * $pageSize}
按年分表
表名只能用 #{} 拼入。多语句正文必须 return:
SELECT order_no, amount, create_time
FROM #{
var y = $year != null ? $year : year(now());
return 'orders_' + y
}
WHERE status = 'completed'
公共表表达式
WITH dept_fee AS (
SELECT dept_code, SUM(fee) AS total_fee
FROM outpatient_visit
WHERE visit_date >= $startDate AND visit_date < $endDate
GROUP BY dept_code
)
SELECT d.dept_name, f.total_fee
FROM dept_fee f
JOIN department d ON d.dept_code = f.dept_code
ORDER BY f.total_fee DESC
注意事项
常见错误对照
| 错误写法 | 后果 | 正确写法 |
|---|---|---|
WHERE status = $$config.status |
裸 $$config 不会被转换 |
${$$config.status} |
IN (#{$ids})、#{$list.map(...)} 拼集合 |
集合变成 [1, 2, 3],空集合变成 IN (),语法错误 |
参数类型选集合,写 IN (${$ids}) |
#{ var a = [...]; a.contains($f) ? $f : 'x' } 缺 return |
拼出空串,ORDER BY 后为空 |
return a.contains($f) ? $f : 'x' |
LIKE '%${$kw}%' |
占位符在引号内,定义错误 | LIKE ${'%' + $kw + '%'} |
用 ${} 拼表名或子句 |
${} 只绑定为 ?,值像 SQL 片段时报错「表达式看起来在生成动态 SQL 片段」 |
改用 #{} 并做白名单 |
WHERE a = 1; DELETE ... |
中间分号被注入校验拒绝 | 只写一条查询 |
提示:跨库模板优先用
LIMIT n OFFSET m,MySQL 8、MariaDB、PostgreSQL 都支持;MySQL 的LIMIT m, n写法在 PostgreSQL 中不可用。