3.3 参数查询、交叉表与动作查询


3.3 参数查询、交叉表与动作查询

本节摘要:选择查询之外还有三类高频武器:参数查询让一个查询回答一族问题;交叉表把长流水转成宽矩阵,是报表的底座;动作查询负责批量增删改,威力大纪律也大。本节各给一个华彩项目里的真实用例。

前三板斧属于"看数据",这一节的三个兵器开始改变你与数据的协作方式:一次定义、反复提问;行转列、直接印报表;以及批量动手改库。每个都配完整操作过程。

一、参数查询:把条件变成插槽

老板娘的需求很快升级:"能不能我想看几个月就看几个月?"——把写死的 90 天改成运行时问一句即可。做法朴素到近乎简陋:在条件的日期表达式里塞进方括号包裹的一句话:

WHERE 订单.下单日期 >= Date() - [请输入回看天数] AND 订单.业务员 = [请输入业务员姓名 或留空看全部]

运行时弹出输入框填数即得结果,同一个查询模板服务无数临时口径。想再讲究一点,可以在查询属性里声明参数的数据类型(尤其日期型必须声明,否则文本比较会悄悄出错),还可以配合窗体上的下拉框引用控件值替代手工输入——[Forms]![录单台]![选业务员] 这种三段式地址能直接嵌进条件,第 4 章的交互查询全靠这招。

多值槽位还有一个常见痛点:某栏留空表示"不限",怎么让空与非空都工作?一行经典条件搞定:

Like IIf([地区留空则全部]="", "*", [地区留空则全部] & "*")

原理是当输入为空时退化为通配全体,否则按前缀匹配。它不优雅但极其耐用,记下来能用十年。

二、交叉表查询:长表变宽表

老板娘手机里存过一张同行发来的 Excel 矩阵:行为品类、列为月份、格子里是销量。这种透视形态在 Access 里有原生答案——交叉表查询向导或手写 TRANSFORM。以品类乘月份为例:

TRANSFORM Sum([成交单价]*[数量]) AS 月度销售额 SELECT 货品.品类, Sum([成交单价]*[数量]) AS 品类合计 FROM 订单 INNER JOIN (货品 INNER JOIN 订单明细 ON 货品.ID = 订单明细.货品ID) ON 订单.ID = 订单明细.订单ID WHERE 订单.下单日期 >= Date()-180 GROUP BY 货品.品类 PIVOT Format(订单.下单日期, "yyyy-mm");

读法要点:SELECT 行决定左侧钉住什么;PIVOT 行决定横向展开成几列;TRANSFORM 后面的聚合填进格子。Format 函数把日期捏成年月串,月份列自动生成,跨年也不怕。这个查询建好后,第 4 章把它挂进月结报表,一张现成的进货分析表就从机器里流出来了。

判断何时用交叉表有一条经验线:列数可预期且有限(十二个月、六种状态)适合交叉表;列数不定(每来一个新客户就多一列)会让矩阵疯长成灾难,那种需求该去找专门的数据透视组件。

图题:长流水数据到交叉矩阵的三步变形

图题:长流水数据到交叉矩阵的三步变形

三、动作查询:批量动手前的仪式

前三类只读,第四类要动刀。动作查询四兄弟各有分工:更新(Update)、追加(Append)、删除(Delete)、生成表(Make-Table)。举华彩真实用过的一例——纸品涨价,把货品表现价整体上调:

UPDATE 货品 SET 单价 = 单价 * 1.05 WHERE 品类 = "纸品" AND ID NOT IN (SELECT 货品ID FROM 特价协议 WHERE 生效中 = True);

注意子查询排除已签特价的商品——商业规则常比教程复杂,而 SQL 的表达力恰好接得住。

但真正想传达的是动手之前的三个仪式,一笔都不能省:

  1. 先备份文件。整个库复制一份放好,成本五秒,后悔药价值连城;
  2. 先用同条件的选择查询预览。把 UPDATE 改成 SELECT 跑一遍看看会波及哪些行——Access 设计视图其实自带"视图切换",动作状态切回数据表就是预览;
  3. 小批量试跑。条件里临时加 SELECT TOP 10 或日期窄区间,确认行为符合预期再放开范围。

删除查询另有一条铁律:只删自己的测试数据时才允许不带条件运行;生产环境上哪怕界面提示"将删除全部行"出现惊叹号,也必须立刻停下核对。另外记住参照完整性仍会在背后守门——你想删的客户若有订单挂着,引擎会拒绝执行,这是第 2 章投资的红利再次兑现。

四、组合技的两个坑,都很有名

参数与交叉表单独用都乖巧,合在一起就有一个经典报错:给交叉表查询挂上 [请输入年份] 参数后运行,弹出的却是"表达式键入不正确,或者太复杂"。原因是交叉表引擎需要预先固定行标题列的数据类型,而参数在声明之前是黑盒。解法藏在查询属性表里:打开参数表(查询设计菜单里的"参数"按钮),先把 请输入年份 声明为长整型(或对应类型),再回到网格里使用——顺序反了就是不通。

第二个坑出在动作查询与事务的交界。华彩做过一个"月末自动作废超期未付订单"的更新查询,界面一切正常,但偶尔只更新了一半就停——事后发现跑查询的机器恰在那个时段网络抖动。教训是:批量写操作要么放在前端本机对着本地链接稳定执行,要么包进 VBA 的 BeginTrans/CommitTrans 里追求原子性(第 8 章 8.1 会展开)。视徒手动作查询为绝对可靠的人,迟早被一次断网教育。

顺带补一条可复用的变式:把"留空即全部"的技巧升级成区间条件也很常用——付款日期列的条件写成 Between Nz([开始日期],#1/1/1990#) And Nz([结束日期],#12/31/2099#),管理员想查任意时段,全留空则是全历史。三个参数模板配齐后,日常报表九成的临时提问都不再需要你动手改 SQL。

生成表查询单独叮嘱

四兄弟里最容易埋雷的是生成表(Make-Table)。它看似无害——不过是把查询结果落成一张新表——工程上却有两个讲究。

其一,命名必须挂专区前缀且纳入月度清理:生成表是快照不是资产,放任它以正式表的名字躺在导航窗格里,迟早有人把它当成原始数据引用,快照过期后所有下游跟着出错。华彩的约定是统一挂在 SNAP 字头之下并在说明里写明刷新时点。其二,重复运行会整体覆盖同名旧表且不恢复删除的操作没法撤销,因此正式流程里它只能活在两处:受控的每日夜间任务(如性能章的快照刷新)或者你亲手按下按钮的临时分析。任何要进入业务流程核心的环节都不该依赖生成表的产物长期供电。

本节实战手册

  • 参数查询一处定义多处复用,方括号插槽 + 类型声明 + 控件引用三级进阶。
  • "留空即全部"用 Like 配 IIf 一行实现。
  • TRANSFORM 交叉表的口诀:左钉行、上展开列、格里装聚合;列数可控才能用。
  • 动作查询三仪式:备份、预览、小批试跑,顺序不可乱。
  • 参照完整性替你拦住越界的删除,但别拿它当粗心的借口。

查询写得快很重要,跑得慢更致命——下一节专治各种慢。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U