TSQL查询编写求助:将行数据传入子查询而非硬编码值
TSQL最优查询方案:计算符合条件的历史记录数
嘿,我来帮你搞定这个TSQL查询需求!针对你要实现的“每行统计满足特定历史条件的记录数”,我给你两种方案,其中窗口函数的方式性能更优,关联子查询则更直观易懂,你可以根据数据集大小选择。
假设你的数据表名为YourTable,结构包含t_Date(日期)、Area(区域)、Name(名称)、Value(数值)这几个字段,我们的目标是筛选出t_Date = '2018-01-01'的所有行,并为每行计算日期早于当前行、同区域同名称、Value=1的记录总数。
方案一:关联子查询(直观易懂)
这种方式直接用子查询关联当前行的字段,不需要硬编码任何值,完全依赖外部查询的行数据作为条件:
-- 定义目标日期变量,符合你“仅用一个变量”的要求 DECLARE @TargetDate DATE = '2018-01-01'; SELECT t.t_Date, t.Area, t.Name, t.Value, -- 子查询中直接引用外部查询的t.Area、t.Name和t.t_Date,实现动态匹配当前行条件 (SELECT COUNT(*) FROM YourTable sub WHERE sub.Area = t.Area AND sub.Name = t.Name AND sub.Value = 1 AND sub.t_Date < t.t_Date) AS [COUNT Criteria] FROM YourTable t WHERE t.t_Date = @TargetDate;
原理说明
子查询里的sub.Area = t.Area这类条件,会自动匹配外部查询当前行的Area值,每一行都会触发一次子查询计算对应的统计数,逻辑非常直观,适合小数据集使用。
方案二:窗口函数(性能最优)
如果你的数据表数据量较大,关联子查询会因为重复扫描表导致性能下降,这时候窗口函数是更好的选择——它只需要扫描表一次就能完成所有统计:
DECLARE @TargetDate DATE = '2018-01-01'; -- 先通过CTE预计算每个分组的累计统计数 WITH PreAggregated AS ( SELECT t_Date, Area, Name, Value, -- 按Area和Name分组,按日期排序,统计当前行之前所有Value=1的记录数 SUM(CASE WHEN Value = 1 THEN 1 ELSE 0 END) OVER ( PARTITION BY Area, Name ORDER BY t_Date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) AS [RunningCount] FROM YourTable ) -- 最后筛选出目标日期的行即可 SELECT t_Date, Area, Name, Value, [RunningCount] AS [COUNT Criteria] FROM PreAggregated WHERE t_Date = @TargetDate;
原理说明
PARTITION BY Area, Name:把数据按区域和名称分成独立的组ORDER BY t_Date:每个组内按日期排序ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING:只统计当前行之前的所有行(排除当前行本身)SUM(CASE...):累计每个组内符合Value=1的记录数,最终得到每行对应的历史统计数
这种方式避免了重复扫描表,性能比关联子查询提升明显,适合大数据量场景。
内容的提问来源于stack exchange,提问作者user3904868
相关产品推荐
相关产品推荐

