iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 21
1
自我挑戰組

SQL Server 資料庫程式設計/管理/經驗筆記系列 第 21

使用 CROSS APPLY 進行資料表轉置

  • 分享至 

  • xImage
  •  

很多既有系統中存在著用資料行名稱來定義資料儲存內容的設計

非正規化的資料表設計

這時就可以使用 CROSS APPLY 以資料行名稱定義的設計
轉換成以資料列為主的設計

情境
食譜成本資料表

此情境中食譜的資料表有下列成本:份數、時間與電力
使用不同欄位來代表對應的單位與消耗量

原始資料如下

Id	Name			Type01	Unit01	Value01	Type02	Unit02	Value02	Type03	Unit03	Value03
1	芹菜蔬煎餅		份數	人		2.000	時間	分鐘	5.000	NULL	NULL	NULL
2	蛋包日式咖哩飯	份數	人		4.000	時間	分鐘	30.000	電力	度		2.500
3	龍蝦味噌湯		份數	人		8.000	時間	分鐘	15.000	電力	度		1.350

透過 CROSS APPLY 指令就可以將上述資料表內容進行行與列的轉置

--食譜資料表
SELECT a.[Id]
	,a.[Name]
	,b.[Type]
	,b.[Unit]
	,b.[Value]
FROM @RecipeCost a
	CROSS APPLY (
		VALUES ([Type01],[Unit01],[Value01])
			,([Type02],[Unit02],[Value02])
			,([Type03],[Unit03],[Value03])
	) b (
		[Type],[Unit],[Value]
	)
WHERE [Type] IS NOT NULL

轉置完成後的資料內容

-------------------------------------------
Id	Name			Type	Unit	Value
-------------------------------------------
1	芹菜蔬煎餅		份數	人		2.000
1	芹菜蔬煎餅		時間	分鐘	5.000
2	蛋包日式咖哩飯	份數	人		4.000
2	蛋包日式咖哩飯	時間	分鐘	30.000
2	蛋包日式咖哩飯	電力	度		2.500
3	龍蝦味噌湯		份數	人		8.000
3	龍蝦味噌湯		時間	分鐘	15.000
3	龍蝦味噌湯		電力	度		1.350

轉置後就可以將資料表進行調整
將 Type 與 Unit 抽離後建立關聯 ... 等

使用 UNPIVOT 也可以達成類似的效果

下列為完整的 Transact-SQL 片段
可複製到 SQL Server 上執行並確認效果

--食譜資料表
DECLARE @RecipeCost AS TABLE
(
	[Id]			SMALLINT,
	[Name]			NVARCHAR(50),

	[Type01]		NVARCHAR(10),
	[Unit01]		NVARCHAR(5),
	[Value01]		DECIMAL(13,3),	
	[Type02]		NVARCHAR(10),
	[Unit02]		NVARCHAR(5),
	[Value02]		DECIMAL(13,3),
	[Type03]		NVARCHAR(10),
	[Unit03]		NVARCHAR(5),
	[Value03]		DECIMAL(13,3),

	PRIMARY KEY ([Id])
)

--初始化資料內容
INSERT INTO @RecipeCost (
	[Id],[Name]
	,[Type01],[Unit01],[Value01]
	,[Type02],[Unit02],[Value02]
	,[Type03],[Unit03],[Value03]
) VALUES (
	1,N'芹菜蔬煎餅'
	,N'份數',N'人',2
	,N'時間',N'分鐘',5
	,NULL,NULL,NULL
),(
	2,N'蛋包日式咖哩飯'
	,N'份數',N'人',4
	,N'時間',N'分鐘',30
	,N'電力',N'度',2.5
),(
	3,N'龍蝦味噌湯'
	,N'份數',N'人',8
	,N'時間',N'分鐘',15
	,N'電力',N'度',1.35
)

SELECT a.[Id]
	,a.[Name]
	,b.[Type]
	,b.[Unit]
	,b.[Value]
FROM @RecipeCost a
	CROSS APPLY (
		VALUES ([Type01],[Unit01],[Value01])
			,([Type02],[Unit02],[Value02])
			,([Type03],[Unit03],[Value03])
	) b (
		[Type],[Unit],[Value]
	)
WHERE [Type] IS NOT NULL

上一篇
使用 CTE 讓查詢指令碼更好閱讀
下一篇
CURSOR 指標進行資料表操作
系列文
SQL Server 資料庫程式設計/管理/經驗筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言