iT邦幫忙

2

MSSQL LEFT JOIN 只顯示一筆資料

  • 分享至 

  • xImage

請教各位

有A,B兩表是一對多關係,需要JOIN出一個結果
條件為
以A資料筆數為主
B需要判斷STATUS是否為Y
如果Y,則抓取DATE
如果非Y,則抓取最大的DATE

請問MSSQL該如何下?

結構如下

表A

ID NAME
001 王小明
002 張小花
003 李小壯
004 黃小美

表B

ID STATUS DATE
001 N 2024-01-01
001 N 2024-01-10
001 Y 2024-01-28
002 X 2024-03-10
002 N 2024-03-25
003 N 2024-02-05
003 Y 2024-02-13
004 N 2024-01-13
004 R 2024-01-15

預期結果

ID NAME DATE
001 王小明 2024-01-28
002 張小花
003 李小壯 2024-02-13
004 黃小美

以下是原本預期結果 (抱歉已分享解法的大大,預期結果改成欄位留空,抱歉...)

ID NAME DATE
001 王小明 2024-01-28
002 張小花 2024-03-25
003 李小壯 2024-02-13
004 黃小美 2024-01-15

之前是使用UNION來完成的
想再請各位指點是否有其他辦法,謝謝 !

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
3
純真的人
iT邦大師 1 級 ‧ 2024-06-17 12:43:54
最佳解答

恩~是不知道你的日期會不會突然跳大的日期~不然B寫法簡單~

declare @A table(
	ID nvarchar(10)
	,Name nvarchar(10)
)
insert into @A
values('001','王小明')
,('002','張小花')
,('003','李小壯')
,('004','黃小美')

declare @B table(
	ID nvarchar(10)
	,[STATUS] nvarchar(10)
	,[DATE] DATE
)

insert into @B
values('001','N','2024-01-01')
,('001','N','2024-01-10')
,('001','Y','2024-01-28')
,('002','X','2024-03-10')
,('002','N','2024-03-25')
,('003','N','2024-10-05')
,('003','Y','2024-02-13')
,('004','N','2024-01-13')
,('004','R','2024-01-15')

--A寫法
select ID
,Name
,max(Max_Date) Max_Date
from (
	select a.ID
	,a.Name
	,isNull((
		select max( 
			case when c.[STATUS] = 'Y' 
			then [DATE]
			else null
			end
		)
		from @B c
		where A.ID = C.ID
	),[DATE]) Max_Date
	from @A a
	left join @B b on a.ID = b.ID
) k
group by ID
,Name


--B寫法
select a.ID
,a.Name
,max(b.Date) Max_Date
from @A a
left join @B b on a.ID = b.ID
group by a.ID
,a.Name

--C寫法
select a.ID
,a.Name
,isNull(
	max(case when b.[STATUS] = 'Y' then b.Date else null end)
	,max(b.[Date])
) Max_Date
from @A a
left join @B b on a.ID = b.ID
group by a.ID
,a.Name
order by a.ID

厚厚 iT邦新手 1 級 ‧ 2024-06-17 13:29:21 檢舉

不好意思,如果結果如下,是不是無法用B寫法調整了,謝謝

預期結果

ID NAME DATE
001 王小明 2024-01-28
002 張小花
003 李小壯 2024-02-13
004 黃小美

我自己是有直覺地寫出B寫法,但如果遇到要留空,就突然卡住....
好像能在SELECT中去CASE,但無法在WHERE子句中處理

可以這樣~

select a.ID
,a.Name
,isNull(
	max(case when b.[STATUS] = 'Y' then b.Date else null end)
	,max(b.[Date])
) Max_Date
from @A a
left join @B b on a.ID = b.ID
group by a.ID
,a.Name
order by a.ID

https://ithelp.ithome.com.tw/upload/images/20240617/200613693kwocaLAVK.png

厚厚 iT邦新手 1 級 ‧ 2024-06-17 14:17:49 檢舉

感謝大大,我將您的說明調整以下就是我想呈現的方式,謝謝

select a.ID
,a.Name
,isNull( max( case when b.[STATUS] = 'Y'  then b.Date  
else null  end)
,null
) Max_Date
from @A a
left join @B b on a.ID = b.ID
group by a.ID ,a.Name
order by a.ID
2
念戀
iT邦新手 4 級 ‧ 2024-06-17 13:29:23

--C 寫法 改
SELECT 
    A.ID,
    A.NAME,
	CASE
	WHEN  (SELECT count(DATE) FROM #B B WHERE B.ID = A.ID AND B.STATUS = 'Y')>0
	THEN subquery.MAX_DATE
	ELSE  null
	END AS 'DATE'

FROM 
    #A A
CROSS APPLY
    (
        SELECT MAX(B.DATE) AS MAX_DATE
        FROM #B B
        WHERE B.ID = A.ID
    ) AS subquery;
厚厚 iT邦新手 1 級 ‧ 2024-06-17 14:05:29 檢舉

會有錯誤 [無效的資料行名稱 'Max_Date'。]
GROUP BY 會先執行,所以還沒辦法吃到 [AS 'Max_Date']別名

1
may031556
iT邦新手 5 級 ‧ 2024-06-17 13:40:02
SELECT * INTO #A FROM ( VALUES
   ('001',N'王小明')
  ,('002',N'張小花')
  ,('003',N'李小壯')
  ,('004',N'黃小美')
  ) AS A([ID],[NAME])
;

SELECT * INTO #B FROM ( VALUES
 ('001','N',CONVERT(DATE,'2024-01-01'))
,('001','N','2024-01-10')
,('001','Y','2024-01-28')
,('002','X','2024-03-10')
,('002','N','2024-03-25')
,('003','N','2024-02-05')
,('003','Y','2024-02-13')
,('004','N','2024-01-13')
,('004','R','2024-01-15')
) AS B([ID],[STATUS],[DATE])
;

SELECT * FROM #A;
SELECT * FROM #B;

-- version 1
WITH S AS (
 SELECT A.ID, A.NAME, B.[DATE]
 , ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY IIF(STATUS = 'Y',0,1),[DATE]) [SN]
 FROM #A A
 LEFT OUTER JOIN #B B ON A.ID = B.ID
)

SELECT S.ID, S.NAME, S.DATE
FROM S WHERE SN = 1
;

-- version 2 (沒Y留空)
SELECT A.ID, A.NAME, B.[DATE]
FROM #A A
LEFT OUTER JOIN #B B ON A.ID = B.ID AND B.[STATUS] = 'Y'
;
厚厚 iT邦新手 1 級 ‧ 2024-06-17 14:27:03 檢舉

感謝大大回覆
一直沒想到LEFT JOIN在ON後加條件的寫法...很簡單又直覺
但我先嘗試樓上大大們的寫法有成功,已送出最佳解了,抱歉...

2
pilipala
iT邦新手 1 級 ‧ 2024-06-17 23:00:58

參考看看

SELECT 
	A.*  , 
	IIF(IsIncludeY > 0 , MaxDate , NULL) AS [Date]
FROM tblA AS A
	JOIN
		(
			SELECT ID ,
				SUM(IIF([Status] = 'Y' , 1 , 0)) AS IsIncludeY ,
				MAX([Date]) AS MaxDate
			FROM tblB
			GROUP BY ID
		) AS B ON A.ID = B.ID
厚厚 iT邦新手 1 級 ‧ 2024-06-18 09:50:13 檢舉

感謝您,學到一招
程式會這樣用,倒是SQL沒想過用這樣的方式

我要發表回答

立即登入回答