這個挑戰是關於把資料從 ROW 轉成 Column 的商業邏輯,這個應用程式管理員工工作時數,應用程式必須產生每一個員工工作時數資訊,讓其他應用程式來跑。工作時數被分類為一般工作時數、加班時數、假日時數等。
- 資料來源
EmployeeID PayType PayHours ---------- ------- -------- 10001 R 01:30 10001 R 05:15 10001 O 01:00 10001 H 01:30 10002 R 08:00 10002 I 01:00 10002 I 01:30第一個欄位儲存員工工號。第二個欄位儲存付款類別。R 代表 一般工作時數、H 代表 假日等意義。每一個員工付款類別必須累加。產生的結果,每一個員工必須只有一個 ROW 資料。
- 產生結果
Employee Code1 Pay1 Code2 Pay2 Code3 Pay3 Code4 Pay4 -------- ----- ---- ----- ---- ----- ---- ----- ---- 10001 R 6.75 O 1.00 H 1.50 0.00 10002 R 8.00 I 2.50 0.00 0.00
- 規則
- 有 R、O、I 和 H 四種付款類別。
- 每一種類別在每一個 ROW 中,必須產生 codeN 和 payN 欄位;codeN 欄位資料必須為付款類別、payN 欄位資料必須為時數。
- 來源資料表中的資料格式為 HH:MM,MM 這個部分只會是 00、15、30 和 45。
- 產生結果必須是數值形態, 15 分鐘必須用 0.25、30 分鐘必須用 0.5 來呈現,請以此類推。
- 每一個付款類別有其權重,權順序為 R、O、I、H,R 為最高、H 為最低。
- 最後結果必須根據其權重且付款類別必須和時數放在一起。
- 產生的結果必須根據員工編號來排序。
- 產生的結果假如是 0 , 必須為 0.00。
- 個人解法
IF OBJECT_ID('TC42', 'U') IS NOT NULL
BEGIN
DROP TABLE TC42
END
GO
CREATE TABLE TC42
(
EmployeeID VARCHAR(5),
PayType CHAR(1),
PayHours CHAR(5)
)
INSERT INTO TC42 (EmployeeID, PayType, PayHours)
SELECT '10001', 'R', '01:30' UNION ALL
SELECT '10001', 'R', '05:15' UNION ALL
SELECT '10001', 'O', '01:00' UNION ALL
SELECT '10001', 'H', '01:30' UNION ALL
SELECT '10002', 'R', '08:00' UNION ALL
SELECT '10002', 'I', '01:00' UNION ALL
SELECT '10002', 'I', '01:30'
SELECT
T1.EmployeeID,
ISNULL(MAX(CASE WHEN T1.Weight = 1 THEN T1.PayType ELSE NULL END),'') AS Code1,
ISNULL(SUM(CASE WHEN T1.Weight = 1 THEN T1.Pay ELSE NULL END),0) AS Pay1,
ISNULL(MAX(CASE WHEN T1.Weight = 2 THEN T1.PayType ELSE NULL END),'') AS Code2,
ISNULL(SUM(CASE WHEN T1.Weight = 2 THEN T1.Pay ELSE NULL END),0) AS Pay2,
ISNULL(MAX(CASE WHEN T1.Weight = 3 THEN T1.PayType ELSE NULL END),'') AS Code3,
ISNULL(SUM(CASE WHEN T1.Weight = 3 THEN T1.Pay ELSE NULL END),0) AS Pay3,
ISNULL(MAX(CASE WHEN T1.Weight = 4 THEN T1.PayType ELSE NULL END),'') AS Code4,
ISNULL(SUM(CASE WHEN T1.Weight = 4 THEN T1.Pay ELSE NULL END),0) AS Pay4
FROM
(
SELECT
EmployeeID , PayType ,
CAST(mm / 60 + 1.0 * (mm % 60) / 60 AS numeric(3,2)) AS Pay,
Weight
FROM
(
SELECT
EmployeeID , PayType ,
SUM
(
CAST(SUBSTRING(PayHours,1,2) AS smallint) * 60 +
CAST(SUBSTRING(PayHours,4,2) AS smallint)
) AS mm,
ROW_NUMBER() OVER
(
PARTITION BY EmployeeID
ORDER BY
CASE PayType
WHEN 'R' THEN 1
WHEN 'O' THEN 2
WHEN 'H' THEN 3
WHEN 'I' THEN 4
ELSE 0
END
) AS Weight
FROM TC42
GROUP BY EmployeeID , PayType
) AS T
) AS T1
GROUP BY T1.EmployeeID
ORDER BY T1.EmployeeID
- 個人解法邏輯:
- 利用SUBSTRING() 來抓出 PayHours 的時和分,並把時轉成分;利用 ROW_NUMBER() 來產生權重欄位。
- 把整合過的總分除 60 求得小時、模除(%)60 求得剩下的分再除 60 計算比例。
- 針對 EmployeeID 進行 GROUP,利用權重欄位來決定欄位順序,CASE WHEN 撘配 MAX() 和 SUM() 來進行轉置。
- 多欄位 PIVOT 應用
IF OBJECT_ID('TC42', 'U') IS NOT NULL
BEGIN
DROP TABLE TC42
END
GO
CREATE TABLE TC42
(
EmployeeID VARCHAR(5),
PayType CHAR(1),
PayHours CHAR(5)
)
INSERT INTO TC42 (EmployeeID, PayType, PayHours)
SELECT '10001', 'R', '01:30' UNION ALL
SELECT '10001', 'R', '05:15' UNION ALL
SELECT '10001', 'O', '01:00' UNION ALL
SELECT '10001', 'H', '01:30' UNION ALL
SELECT '10002', 'R', '08:00' UNION ALL
SELECT '10002', 'I', '01:00' UNION ALL
SELECT '10002', 'I', '01:30'
SELECT
EmployeeID ,
ISNULL(MAX([pay1]),'') AS code1,
ISNULL(SUM([code1]),0) AS pay1,
ISNULL(MAX([pay2]),'') AS code2,
ISNULL(SUM([code2]),0) AS pay2,
ISNULL(MAX([pay3]),'') AS code3,
ISNULL(SUM([code3]),0) AS pay3,
ISNULL(MAX([pay4]),'') AS code4,
ISNULL(SUM([code4]),0) AS pay4
FROM
(
SELECT
T.EmployeeID , T.PayType , T.mm ,
'pay' + CAST(T.Weight AS CHAR(1)) AS Weight ,
'code' + CAST(T.Weight AS CHAR(1)) AS Weight2
FROM
(
SELECT
EmployeeID , PayType ,
CAST
(
SUM
(
CAST(LEFT(PayHours,2) AS smallint) * 60 +
CAST(RIGHT(PayHours,2) AS smallint)
) / 60.0
AS numeric(3,2)
) AS mm,
ROW_NUMBER() OVER
(
PARTITION BY EmployeeID
ORDER BY
CASE PayType
WHEN 'R' THEN 1
WHEN 'O' THEN 2
WHEN 'H' THEN 3
WHEN 'I' THEN 4
ELSE 0
END
) AS Weight
FROM TC42
GROUP BY EmployeeID , PayType
) AS T
) AS P
PIVOT
(
MAX(PayType) FOR Weight IN ([pay1],[pay2],[pay3],[pay4])
) AS PV
PIVOT
(
SUM(mm) FOR Weight2 IN ([code1],[code2],[code3],[code4])
) AS PV2
GROUP BY EmployeeID
- 多欄位 PIVOT 重點
PIVOT 的 SourceTable 必須先整理好,多欄位 PIVOT 只進行轉置動作,無法利用彙總函數來進行加總
![[SQL] 動態欄位轉置](https://farm8.staticflickr.com/7013/6722833779_7d8e6bb481_o.jpg)
沒有留言:
張貼留言