复合枚举在SQL Server中的应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yenange/article/details/82313650

相关贴子: https://bbs.csdn.net/topics/392439957

状态字段, 一般是单纯的, 但如果有复合的状态怎么办?

比如考勤, 一个人一天之中, 既有迟到, 又有早退, 那如何设计这个状态字段?

用户考勤, 共 6 种状态:

--userState:
--1 出勤       1
--2 请假      10
--4 公差     100
--8 迟到    1000
--16 早退  10000
--32 旷工 100000

如上, 设计成 二进制对应的值, 前面是 1, 后面全是 0,  而且位置全部错开, 这样相加时, 绝对不会有重合的问题出现。

--如果需要组合:
--既有 迟到,也有早退
--SELECT 8 | 16
/*
24
*/

那这种字段的值, 到时候如何查询出是哪几种组合?

USE tempdb
GO
IF OBJECT_ID('t') IS NOT NULL DROP TABLE t
GO
CREATE TABLE t(
	id INT IDENTITY(1,1) PRIMARY KEY,
	userId INT NOT NULL,
	addinsDate DATE NOT NULL,
	seg INT,				--班次时段 0 上午 1 下午 2 晚上	
	userState INT,			--1 出勤 2 请假 4 公差 8 迟到 16 早退 32 旷工
	userStateSplit AS 
	CASE WHEN userState IN (1,2,4,8,16,32) THEN LTRIM(userState)
			WHEN userState = 3 THEN '1,2'
			WHEN userState = 5 THEN '1,4'
			WHEN userState = 9 THEN '1,8'
			WHEN userState = 17 THEN '1,16'
			WHEN userState = 33 THEN '1,32'
			WHEN userState = 6 THEN '2,4'
			WHEN userState = 10 THEN '2,8'
			WHEN userState = 18 THEN '2,16'
			WHEN userState = 34 THEN '2,32'
			WHEN userState = 12 THEN '4,8'
			WHEN userState = 20 THEN '4,16'
			WHEN userState = 36 THEN '4,32'
			WHEN userState = 24 THEN '8,16'
			WHEN userState = 40 THEN '8,32'
			WHEN userState = 48 THEN '16,32'
			WHEN userState = 7 THEN '1,2,4'
			WHEN userState = 11 THEN '1,2,8'
			WHEN userState = 19 THEN '1,2,16'
			WHEN userState = 35 THEN '1,2,32'
			WHEN userState = 13 THEN '1,4,8'
			WHEN userState = 21 THEN '1,4,16'
			WHEN userState = 37 THEN '1,4,32'
			WHEN userState = 25 THEN '1,8,16'
			WHEN userState = 41 THEN '1,8,32'
			WHEN userState = 49 THEN '1,16,32'
			WHEN userState = 14 THEN '2,4,8'
			WHEN userState = 22 THEN '2,4,16'
			WHEN userState = 38 THEN '2,4,32'
			WHEN userState = 26 THEN '2,8,16'
			WHEN userState = 42 THEN '2,8,32'
			WHEN userState = 50 THEN '2,16,32'
			WHEN userState = 28 THEN '4,8,16'
			WHEN userState = 44 THEN '4,8,32'
			WHEN userState = 52 THEN '4,16,32'
			WHEN userState = 56 THEN '8,16,32'
			WHEN userState = 15 THEN '1,2,4,8'
			WHEN userState = 23 THEN '1,2,4,16'
			WHEN userState = 39 THEN '1,2,4,32'
			WHEN userState = 29 THEN '1,4,8,16'
			WHEN userState = 45 THEN '1,4,8,32'
			WHEN userState = 57 THEN '1,8,16,32'
			WHEN userState = 30 THEN '2,4,8,16'
			WHEN userState = 46 THEN '2,4,8,32'
			WHEN userState = 58 THEN '2,8,16,32'
			WHEN userState = 60 THEN '4,8,16,32'
			WHEN userState = 31 THEN '1,2,4,8,16'
			WHEN userState = 47 THEN '1,2,4,8,32'
			WHEN userState = 61 THEN '1,4,8,16,32'
			WHEN userState = 63 THEN '1,2,4,8,16,32'
	END
)
GO
INSERT INTO t VALUES (1,'2018-08-01',0,1)
INSERT INTO t VALUES (1,'2018-08-01',1,1)
INSERT INTO t VALUES (1,'2018-08-02',0,2)
INSERT INTO t VALUES (1,'2018-08-02',0,1)
INSERT INTO t VALUES (2,'2018-08-02',0,24)
GO
SELECT 
userId
,addinsDate
,SUM(CASE WHEN ','+userStateSplit+',' LIKE '%,1,%' THEN 1 ELSE 0 END) AS [出勤]
,SUM(CASE WHEN ','+userStateSplit+','  LIKE '%,2,%' THEN 1 ELSE 0 END) AS [请假]
,SUM(CASE WHEN ','+userStateSplit+','  LIKE '%,4,%' THEN 1 ELSE 0 END) AS [公差]
,SUM(CASE WHEN ','+userStateSplit+','  LIKE '%,8,%' THEN 1 ELSE 0 END) AS [迟到]
,SUM(CASE WHEN ','+userStateSplit+','  LIKE '%,16,%' THEN 1 ELSE 0 END) AS [早退]
,SUM(CASE WHEN ','+userStateSplit+','  LIKE '%,32,%' THEN 1 ELSE 0 END) AS [旷工]
FROM t 
GROUP BY userId,addinsDate


根据 mingqing6364 兄的评论, 改了一下, 现在非常完美了, 用计算列比较简洁轻松, 不用计算列也能得到结果:

USE tempdb
GO
IF OBJECT_ID('t') IS NOT NULL DROP TABLE t
GO
CREATE TABLE t(
	id INT IDENTITY(1,1) PRIMARY KEY,
	userId INT NOT NULL,
	addinsDate DATE NOT NULL,
	seg INT,				--班次时段 0 上午 1 下午 2 晚上	
	userState INT,			--1 出勤 2 请假 4 公差 8 迟到 16 早退 32 旷工
	userStateSplit AS 
		STUFF((
			CASE WHEN userState & 1 = 1 THEN ',1' ELSE '' END
			+
			CASE WHEN userState & 2 = 2 THEN ',2' ELSE '' END
			+
			CASE WHEN userState & 4 = 4 THEN ',4' ELSE '' END
			+
			CASE WHEN userState & 8 = 8 THEN ',8' ELSE '' END
			+
			CASE WHEN userState & 16 = 16 THEN ',16' ELSE '' END
			+
			CASE WHEN userState & 32 = 32 THEN ',32' ELSE '' END
		),1,1,'')
)
GO
INSERT INTO t VALUES (1,'2018-08-01',0,1)
INSERT INTO t VALUES (1,'2018-08-01',1,1)
INSERT INTO t VALUES (1,'2018-08-02',0,2)
INSERT INTO t VALUES (2,'2018-08-02',0,48)
INSERT INTO t VALUES (2,'2018-08-02',0,24)
GO
SELECT * FROM t
--
SELECT 
userId
,addinsDate
,SUM(CASE WHEN userState & 1 = 1 THEN 1 ELSE 0 END) AS [出勤]
,SUM(CASE WHEN userState & 2 = 2 THEN 1 ELSE 0 END) AS [请假]
,SUM(CASE WHEN userState & 4 = 4 THEN 1 ELSE 0 END) AS [公差]
,SUM(CASE WHEN userState & 8 = 8 THEN 1 ELSE 0 END) AS [迟到]
,SUM(CASE WHEN userState & 16 = 16 THEN 1 ELSE 0 END) AS [早退]
,SUM(CASE WHEN userState & 32 = 32 THEN 1 ELSE 0 END) AS [旷工]
FROM t 
GROUP BY userId,addinsDate

猜你喜欢

转载自blog.csdn.net/yenange/article/details/82313650
今日推荐