SQL如何实现左单一匹配(两种方法)

文章介绍了如何在SQL中进行左单一匹配连接,以避免数据因连接而扩大。通过使用ROW_NUMBER()函数或FIRST_ROWS提示,可以选取每个学生的一条特定成绩记录,如最新或任意一条。方法1适合被匹配表较小的情况,方法2适用于主表数据小的情况。
摘要由CSDN通过智能技术生成

SQL的表连接中,如果主表中同一条数据对应被连接表有多条数据,则连接后数据会被扩大,但有时候我们希望数据不要被扩大,与主表中数据条数保持一致,即实现左单一匹配连接。

假设我们有学生信息表TEST_TAB_STUDENTS和学生成绩表TEST_TAB_SCORE,如下:

TEST_TAB_STUDENTS:

NAME

STU_NUMBERCLASSGRADE
张三23578三班五年级
李四23632二班五年级
王五23448一班六年级
赵六32251三班四年级

TEST_TAB_SCORE:

NAMEMONTH_TIMEKEYCHINESEMATHSENGLISHPHYSICSCHEMISTRYBIOLOGY
张三2023M01726267658971
张三2023M02807083797697
张三2023M03689063947093
张三2023M04868695726972
张三2023M05739699839582
李四2023M02866170619090
李四2023M03749373908466
李四2023M04998961867386
李四2023M05889477996679
李四2023M06686385656675
王五2023M03699464956796
王五2023M04916194839174
王五2023M05667482747797
王五2023M06968482878370
王五2023M07988178916976
赵六2023M01959193746964
赵六2023M02906477946395
赵六2023M03669566618091
赵六2023M04966776828775
赵六2023M05926195987997

如果需要将学生表中匹配出每个学生的任意一笔成绩(或按一定顺序一条),则需要用到左单一匹配。

1. 先将被连接表排序后取一条(如果是任意一条则可以写order by 1)

SELECT A.NAME,A.STU_NUMBER,A.CLASS,A.GRADE,C.MONTH_TIMEKEY,C.CHINESE,C.MATHS,C.ENGLISH,C.PHYSICS,C.CHEMISTRY,C.BIOLOGY
FROM TEST_TAB_STUDENTS A
--如果需要按某一列排序,例如取时间最后的一条成绩,可改为ORDER BY MONTH_TIMEKEY DESC
LEFT JOIN (SELECT B.*,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY 1) RN FROM TEST_TAB_SCORE B) C
ON A.NAME = C.NAME 
WHERE C.RN = 1

输出:

NAMESTU_NUMBERCLASSGRADEMONTH_TIMEKEYCHINESEMATHSENGLISHPHYSICSCHEMISTRYBIOLOGY
张三23578三班五年级2023M01726267658971
李四23632二班五年级2023M06686385656675
王五23448一班六年级2023M06968482878370
赵六32251三班四年级2023M01959193746964

2. 通过hint:first_rows查找被连接表中按一定顺序后的第一条(或任意一条)

如果连接后只需查找一列,如语文成绩,则可直接查找:

--根据MONTH_TIMEKEY排序取最后一条数据
SELECT A.NAME,A.STU_NUMBER,A.CLASS,A.GRADE,
(SELECT /*+ FIRST_ROWS*/CHINESE
	FROM
	(SELECT CHINESE 
	FROM TEST_TAB_SCORE B
	WHERE A.NAME = B.NAME
	ORDER BY MONTH_TIMEKEY DESC 
	) WHERE ROWNUM<=1
) AS CHINESE
FROM TEST_TAB_STUDENTS A

--不需要排序取任意一条
SELECT A.NAME,A.STU_NUMBER,A.CLASS,A.GRADE,
(SELECT /*+ FIRST_ROWS*/CHINESE
	FROM TEST_TAB_SCORE B
	WHERE A.NAME = B.NAME
    AND ROWNUM<=1
) AS CHINESE
FROM TEST_TAB_STUDENTS A

如果连接后需要的列较多,如各科成绩都需要,则重复查找会耗费性能,可以先查找出ROWID,再左连接:

--根据MONTH_TIMEKEY排序取最后一条数据
SELECT AA.NAME,AA.STU_NUMBER,AA.CLASS,AA.GRADE,C.MONTH_TIMEKEY,C.CHINESE,C.MATHS,C.ENGLISH,C.PHYSICS,C.CHEMISTRY,C.BIOLOGY
FROM (
	SELECT A.NAME,A.STU_NUMBER,A.CLASS,A.GRADE,
	(SELECT /*+ FIRST_ROWS*/ROW_ID
		FROM
		(SELECT ROWID ROW_ID 
		FROM TEST_TAB_SCORE B
		WHERE A.NAME = B.NAME
		ORDER BY MONTH_TIMEKEY DESC
		) WHERE ROWNUM<=1
	) AS ROW_ID
	FROM TEST_TAB_STUDENTS A
) AA 
LEFT JOIN TEST_TAB_SCORE C ON AA.ROW_ID = C.ROWID

--不需要排序取任意一条
SELECT AA.NAME,AA.STU_NUMBER,AA.CLASS,AA.GRADE,C.MONTH_TIMEKEY,C.CHINESE,C.MATHS,C.ENGLISH,C.PHYSICS,C.CHEMISTRY,C.BIOLOGY
FROM (
	SELECT A.NAME,A.STU_NUMBER,A.CLASS,A.GRADE,
	(SELECT /*+ FIRST_ROWS*/ ROWID ROW_ID 
		FROM TEST_TAB_SCORE B
		WHERE A.NAME = B.NAME
		AND ROWNUM<=1
	) AS ROW_ID
	FROM TEST_TAB_STUDENTS A
) AA 
LEFT JOIN TEST_TAB_SCORE C ON AA.ROW_ID = C.ROWID

3. 两种方法比较:

两种方式均能实现需求,在不同场景性能表现有所不同:

方法1采用排序后hash join的方式,适用于主表(TEST_TAB_STUDENTS)较大,而被匹配表(TEST_TAB_SCORE)较小的情况,因为被匹配表需要全部排序;

方法2则采用first_row方式迭代取出B表的第一条数据,适用于主表(取出的数据)较小,而B表较大的情况。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值