SQL Server中用APPLY作成max(m, n)而非m*n的表连接效果

SQL Server物理连接操作深度解析:Nested Loops、Hash Match与Merge Join选型指南 JOIN是SQL查询的核心逻辑,但数据库真正执行时必须将其转化为底层物理操作——这正是SQL Server性能分化的关键起点。理解Nested Loops(嵌套循环)、Hash Match(哈希连接)和Merge Join(合并连接)的本质差异,需从数据流模式、内存占用、I/O特征与CPU消耗四维切入:前者依赖索引查找与小驱动,适合高选择性场景;中者以哈希实现线性匹配,但极易因内存不足Spill至TempDB;后者要求双有序,I/O高效却对索引结构极为敏感。这些物理连接操作的选择直接受统计信息准确性、 阅读详情

众所周知,JOIN只能造成m*n的表连接效果。但有的时候,我需要的仅仅是将两个表列举在一起,即造成max(m,n)的效果。

举个例子:有两张表要连接在一起,表A的结构如下图所示:Table1
表B的结构如下图所示:Table2
现在,我们想要将两张表连接成如下图所示的效果:这里写图片描述
也就是,我们只想先按照合同号,找出两张表中同一个合同的数据,然后将两张表的列合并起来。表A列在左边,表B列在右边。这就是max(m,n)的效果,m是表A的行数,n是表B的行数。
如果我们用JOIN连接的话,就会是如下图的效果:用JOIN连接的效果

我首先想,如果只有一个合同的数据,那我怎么能并列两张表,我想到了用行号,SQL Server中提供了内置函数row_number()为查询结果提供行号,这样我们就可以在CONTRACT_ID相同的情况下,用行号进行连接了。SQL代码如下:

ALTER FUNCTION dbo.getOneContractDelayInterestReport(@contract_id int)
RETURNS TABLE
AS
RETURN
(select ABC.*, D.RECEIVE_DATE as 实收逾期利息日, D.ActualPayDelayInterest as 实收逾期利息额
from (select row_number() over (order by isnull(Q.CONTRACT_ID, A.CONTRACT_ID), isnull(Q.ISSUE_NO, A.ISSUE_NO),isnull(Q.SETTLEMENT_END_DATE, A.PLAN_DATE)) as RowNo,
        isnull(Q.CONTRACT_ID, A.CONTRACT_ID) as CONTRACT_ID,
        isnull(Q.ISSUE_NO, A.ISSUE_NO) as ISSUE_NO, 
        A.PLAN_DATE as 应收款日, 
        A.PLAN_AMOUNT as 应收款额,
        Q.RECEIVE_DATE as 实收款日,
        Q.RECEIVE_AMOUNT as 实收款额,
        Q.SETTLEMENT_START_DATE as 计息开始日,
        Q.SETTLEMENT_END_DATE as 计息结束日,
        Q.COMPUTED_AMOUNT as 计算基准额,
        Q.SettleDays as 计息天数,
        Q.OVERDUE_AMOUNT as 逾期利息,
        Q.ADJUST_AMOUNT as 减免逾期利息
    from (select * from dbo.SETTLEMENT_PLAN_SCCMF where CONTRACT_ID = @contract_id) A
    full join (select C.CONTRACT_ID, C.ISSUE_NO,
        B.RECEIVE_DATE, B.RECEIVE_AMOUNT,
        C.SETTLEMENT_START_DATE, C.SETTLEMENT_END_DATE,
        C.COMPUTED_AMOUNT, DATEDIFF(day, C.SETTLEMENT_START_DATE, C.SETTLEMENT_END_DATE) as SettleDays,
        C.OVERDUE_AMOUNT, C.ADJUST_AMOUNT
    from (select * from dbo.SETTLEMENT_ACTUAL_SCCMF where CONTRACT_ID = @contract_id) B
    right join (select * from dbo.SETTLEMENT_PLAN_SCCMF_OVERDUE where CONTRACT_ID = @contract_id) C
    on B.CONTRACT_ID = C.CONTRACT_ID
    and B.ISSUE_NO = C.ISSUE_NO
    and  B.RECEIVE_DATE = C.SETTLEMENT_END_DATE) Q
    on A.CONTRACT_ID = Q.CONTRACT_ID
    and A.ISSUE_NO = Q.ISSUE_NO
    and A.PLAN_DATE = Q.SETTLEMENT_START_DATE) ABC
full join
(select row_number() over (order by CONTRACT_ID, RECEIVE_DATE) as RowNo, CONTRACT_ID, RECEIVE_DATE, sum(RECEIVE_AMOUNT) as ActualPayDelayInterest
    from dbo.SETTLEMENT_ACTUAL_SCCMF_OVERDUE
    where CONTRACT_ID = @contract_id 
    group by CONTRACT_ID, RECEIVE_DATE) D
on ABC.RowNo = D.RowNo
);
GO

在此,我将contract_id作为参数写了一个函数,这可满足一个合同情况下的连接,从倒数第三行的join条件可以看到我用行号作为连接条件。此一个合同的情况下的连接效果如下图所示,假设我们连接1006合同:一个合同的连接,使用row_number()

接着就是APPLY的用武之地了。先看微软上APPLY的一个例子
这里有一个函数fn_getsubtree(),它以Departments表的deptmgrid(部门经理ID)为参数,返回该部门的所有成员。例如HR部门的部门经理的ID是2,即Andrew,接着找Andrew的下属们,找到了Steven和Michael,他们的经理都是Andrew。功能说完。

这里可以明晰看到Apply的作用,它把左边表(Departments表)的每一行依次作为输入,放到右边的函数中处理,假设函数返回m行,那么就输出m行,左边的那一行输入则重复输出m次。。。如此,如果左表有n行输入,则最终可产生n*m行输出。这正是我们所需的功能!当合并两表时,一个合同我们可以用行号连接,那么多个合同时,我们只需要将所有的合同号作为APPLY左侧的输入,然后就能得到我们所需的所有的连接后的合同的输出。

代码如下(调用在上面写的函数):

ALTER PROCEDURE [dbo].[SP_CLM1701_OVERDUE_INTEREST_REPORT
@AGENT_ID nvarchar(6),

@DELIVERY_DATE_LEFT nvarchar(10),

@DELIVERY_DATE_RIGHT nvarchar(10),

@CONTRACT_NO nvarchar(50),

@CLOSING_DATE nvarchar(10)

AS
declare @sql nvarchar(max)
declare @whereForContract nvarchar(max)

set @whereForContract = ' where CONTRACT_TYPE = ''FS'' and CONTRACT_STATUS = ''3'''

if(@CONTRACT_NO <> '')
begin
set @whereForContract += ' and CONTRACT_NO = '''+@CONTRACT_NO+''''
end

if(@AGENT_ID <> '')
begin
set @whereForContract += ' and AGENT_ID = '''+@AGENT_ID+''''
end

if(@DELIVERY_DATE_LEFT <>'')
begin
set @whereForContract += ' and DELIVERY_DATE >= '''+@DELIVERY_DATE_LEFT+''''
end

if(@DELIVERY_DATE_RIGHT <>'')
begin
set @whereForContract += ' and DELIVERY_DATE <= '''+@DELIVERY_DATE_RIGHT+''''
end

set @sql = 
'
select A.CONTRACT_NO, A.MACHINE_TYPE, A.MACHINE_NO, A.END_USER_ID, A.CUSTOMER_NAME, A.AGENT_ID, A.COMPANY_NAME, A.DELIVERY_DATE, A.TOTAL_AMOUNT, B.*
from
(select C.*, MST_CUSTOMER.CUSTOMER_NAME, MST_COMPANY.COMPANY_NAME
from (select * from dbo.MACHINE_CONTRACT_SCCMF ' +@whereForContract+ ') C, dbo.MST_CUSTOMER, dbo.MST_COMPANY
where C.END_USER_ID = MST_CUSTOMER.CUSTOMER_ID
and C.AGENT_ID = MST_COMPANY.COMPANY_ID) A
cross apply getOneContractDelayInterestReport(A.CONTRACT_ID,'''+@CLOSING_DATE+''') AS B
'


exec (@sql)

以上存储过程所用的函数与上面所写参数略有不同,因为最终还多了一个参数作为条件,不过不影响解释。以上@sql最末可以看到我们将A作为Apply的输入。

最终调用该存储过程即可:

DECLARE @return_value int

EXEC    @return_value = [dbo].[SP_CLM1701_OVERDUE_INTEREST_REPORT]
        @AGENT_ID = NULL,
        @DELIVERY_DATE_LEFT = N'2016/05/30',
        @DELIVERY_DATE_RIGHT = N'2016/06/01',
        @CONTRACT_NO = NULL,
        @CLOSING_DATE = N'2016/06/05'

SELECT  'Return Value' = @return_value

GO

最终效果已贴在上面。


SQL JOIN 实战指南:语义、性能与执行计划深度解析 JOIN 是关系型数据库中最基础也最易误用的核心操作,其本质是数据集合间的逻辑关系建模,而非简单的语法组合。理解 INNER/LEFT/CROSS JOIN 的语义差异,是避免数据丢失与逻辑错误的前提;掌握 ON 与 WHERE 的执行阶段区别,可规避外连接失效等隐蔽 Bug;而 CROSS APPLY 与 OUTER APPLY 的价值在于支持延迟计算与可选衍生逻辑,直击复杂业务场景。结合执行计划分析、索引覆盖与统计信息优化,JOIN 性能可实现数量级提升。本文聚焦 SQL Server 生产环境高频问题 阅读详情

相关推荐

SQL Server T-SQL性能优化十大实战习惯

T-SQL性能优化是SQL Server数据库高效运行的核心能力,其本质在于理解查询执行原理、掌握执行计划分析方法,并通过参数化查询、索引设计、统计信息更新等关键技术控制资源消耗。高性能T-SQL不是语法堆砌,而是对IO读取、CPU时间、内存授予等可测量指标的精准调控。典型应用场景包括高并发电商库存扣减、医疗大数据分页查询、金融级事务一致性保障等。本文聚焦生产环境高频痛点,结合执行计划分析与真实压测数据,系统阐述从列选择、函数使用、事务隔离到临时对象选型等十大可落地、可验证、可量化的T-SQL性能优化习惯。

diaozhiwa5526的博客 362

sql server 2008中的apply运算符使用方法

sql server 2008中的apply运算符使用方法,需要的朋友可以参考一下

SQL Server分页优化实战:从ROW_NUMBER到键集分页

分页查询是数据库性能瓶颈的高发场景,其本质是排序、筛选与数据定位三者的协同问题。传统ROW_NUMBER()分页因强制全集排序和编号,导致CPU飙升、tempdb压力剧增及索引失效;而OFFSET-FETCH通过语义化跳过机制显著降低IO与内存开销,但大数据偏移仍受限于线性跳过成本。真正可持续的高性能分页依赖键集分页(游标分页)——以排序键值为锚点,结合覆盖索引与过滤索引,实现恒定复杂度的索引Seek。本文聚焦SQL Server环境,深入解析ROW_NUMBER()隐性代价、OFFSET-FETCH实测差

a6t2007的博客 353

SQL Server中CROSS APPLY连接操作

SQL Server中CROSS APPLY连接操作示例文档

zxrhhm的博客 2193

sql server APPLY使用

这个是单个返回值,要select,还要别名。这个是table返回值,直接用。

JavaDaBaiCai的博客 238

SQL ServerAPPLY操作符

SQL Server 中的APPLY操作符用于将值函数(或子查询)与外部查询的每一行关联执行,生成组合结果。它类似于JOIN,但更灵活,尤其适用于需要为每一行动态计算结果的场景。APPLY和。

weixin_46182438的博客 658

SqlServer中关于apply的两种形式cross apply 和 outer apply的详细说明

类似INNER JOIN,仅返回匹配的行。: 类似LEFT JOIN,即便没有匹配的结果,也返回外部的行。应用选择使用当只需要包含匹配结果时。使用当需要返回所有外部的行,无论是否有匹配时。

极客神殿 1492

浅析 SQL Server 的 CROSS APPLY 和 OUTER APPLY 查询 - 第一部分

你可能知道,SQL Server 中的 JOIN 操作用于联接两个或多个。但是,在 SQL Server 中,JOIN 操作不能用于将值函数的输出联接起来。如果你没有听说过值函数,这些函数是以的形式返回数据。为了连接两个达式,SQL Server 2005 引入了 APPLY 运算符。在本篇文章中,我们将了解 APPLY 运算符与常规 JOIN 的不同之处。......

Navicat 官方账号 2446

SQL Server2008中CROSS APPLY的应用范例() - 将一个或多个字段内用逗号分隔的内容分成多条记录

SQL Server2008中CROSS APPLY的应用范例                        ——将一个或多个字段内用逗号分隔的内容分成多条记录 DECLARE @DutyLst VARCHAR(MAX); DECLARE @DutyNames NVARCHAR(MAX); SET @DutyLst = '793f2b96-0818-491f-839a-3bf431

秋水之城 2080

SQL Server单日4.3亿写入实战:分区切换与内存优化混合架构

在高并发IoT场景下,关系型数据库的写入瓶颈往往不在引擎能力,而在数据组织方式与IO路径设计。理解分区的元数据切换原理、内存优化的持久化机制差异,是突破传统TPS天花板的关键。SQL Server的分区切换(SWITCH)本质是文件页指针交换,零日志、无锁、亚毫秒级完成;而SCHEMA_ONLY内存则将写入降维为纯内存拷贝,彻底规避日志和磁盘IO。这种组合技术方案,既满足金融级ACID与审计合规要求,又支撑原始数据100ms内端到端处理,广泛适用于智能电、车载终端、工业传感器等需强一致性+高吞吐+低

rongdmmap的博客 344

如何利用SQL子查询处理一对多数据_关联查询优化

子查询在一对多场景易致重复或错误结果,应优先用EXISTS替代IN;比如查“有订单的用户”,IN 没问题;通用写法:ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC),再外层 WHERE rn = 1PostgreSQL / SQL Server / MySQL 8.0+ 支持,但 SQLite 不支持窗口函数,得退回到 JOIN + 聚合或应用层处理注意 PARTITION BY 字段必须和主关联字段一致,否则分组错位;

2401_83595681的博客 230

SQL Server非聚集索引四大核心能力:覆盖、连接、交叉、过滤

非聚集索引是SQL Server查询性能的底层支柱,其本质能力由查询优化器动态判定,而非静态分类。基于B+树结构与执行计划生成机制,同一索引可依谓词、投影和连接条件的不同,分别承担覆盖(避免Key Lookup)、连接(加速Nested Loops内循环)、交叉(多索引结果集求交)和过滤(高效Seek定位)四类角色。这些能力直接决定IO开销、响应延迟与系统吞吐量,尤其在OLTP高频查询、星型模型JOIN及多条件报场景中影响显著。理解其原理,结合INCLUDE列、过滤索引、统计信息维护与执行计划反推等工程实

diaojin6880的博客 330

SQL Server INSERT性能深度解析:从语法到底层资源消耗

INSERT是关系型数据库中最基础的DML操作,但在SQL Server中,它远不止语法层面的数据写入——其执行过程深度耦合事务日志、锁机制、统计信息更新、索引维护与tempdb资源调度。理解INSERT的执行原理,有助于识别隐式转换、触发器开销、页分裂、U锁争用等高频性能陷阱;掌握执行计划中的Compute Scalar、Table Spool、Index Insert等关键算子,可精准定位‘简单插入’背后的高延迟根源。本文聚焦SQLServer Insert实际运行时的行为特征与工程调优路径,覆盖高并发

dejz8829的专栏 442

SQL Server用户定义存储过程实战指南:从创建到治理

存储过程是数据库中预编译、可复用、带事务和权限控制的数据操作单元,其核心原理在于执行计划缓存、参数化查询与最小权限模型。相比应用层拼接SQL,它显著降低维护成本、规避SQL注入风险、提升高并发查询性能,并支撑细粒度审计与SLA保障。在SQL Server中,正确使用CREATE OR ALTER、参数化WHERE条件、sp_executesql动态构建、WITH ENCRYPTION与角色权限分离等技术,能将存储过程打造为稳定可靠的数据服务契约。本文聚焦用户定义存储过程(usp_前缀)、参数化查询与生产级治

weixin_34269583的博客 427

SQL Server触发器实战避坑指南:After与Instead Of选型、事务控制与审计系统设计

触发器是SQL Server中实现数据一致性、审计日志和业务拦截的关键机制,其核心在于理解DML与DDL触发器的执行时序、事务上下文(如@@TRANCOUNT)及隐式事务行为。After触发器在约束校验后执行,适用于日志记录与通知;Instead Of触发器则在约束前接管,是唯一能绕过CHECK、DEFAULT、外键级联的‘数据越狱’手段。二者选型错误将直接导致超卖、日志丢失或递归崩溃。结合保存点(Savepoint)、集合操作替代游标、EVENTDATA()解析等工程实践,可构建高可用审计系统。本文聚焦生

clugcpne10995的博客 2057

SQL Server数学达式与聚合函数实战避坑指南

SQL中的数学运算与聚合函数远不止基础语法,其本质是数据语义、执行计划与业务规则的深度耦合。理解四则运算在执行引擎中作为标量操作符的逐行计算特性,可避免CPU过载与索引失效;掌握NULL在算术链中的传播机制,是保障财务类指标准确性的前提;而聚合函数如SUM、AVG、STDEV等,不仅涉及GROUP BY的逻辑契约,更需区分样本/总体统计语义。结合计算列PERSISTED、窗口函数、条件聚合与GROUPING SETS等高级技术,才能构建高性能、高可信的业务指标体系——这正是SQL Server数据工程师在真

weixin_34124651的博客 310

SQL驱动Power BI:数据分析师的实战工作流与避坑指南

SQL是现代BI工程的底层语言,它定义了数据获取、转换与建模的逻辑起点。理解SQL与Power BI的协同原理,本质是掌握数据管道的控制权——从连接协议(如OLE DB/SqlConnection)、查询折叠机制,到Import与DirectQuery两种执行模式的算力分配逻辑。这种能力带来显著技术价值:降低内存占用、提升刷新效率、保障审计可追溯性,并支撑星型模型构建与行级安全等企业级需求。典型应用场景包括零售销售分析、金融实时风控看板、制造设备IoT数据聚合等。本文聚焦SQL with Power BI这

weixin_30421809的博客 486

SQL Server 2012新增函数实战指南:窗口计算、逻辑判断与日期处理

SQL Server窗口函数是实现高效行间计算(如环比、首末值)的核心技术,其原理基于OVER子句定义的逻辑分区与有序框架,相比自连接或游标可显著降低时间复杂度和资源开销;IIF、CHOOSE等逻辑函数则将T-SQL从声明式语言推向类编程体验,提升可读性与维护性。这类内置函数具备零部署、高稳定、强兼容的技术价值,广泛应用于金融报生成、BI趋势分析、ERP历史数据归档等需兼顾性能与可维护性的生产场景。本文聚焦SQL Server 2012首批落地的关键函数,结合真实压测数据与避坑经验,系统解析LEAD/LA

dingguayi7025的博客 480
上一篇: 局域网机器间传输大文件,文件共享是正路
youngsend
博客等级 码龄17年 34粉丝 43原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值