我必须检查一名工人是否具备所有必需的技能。这是通过将工人技能组合与所需的一组技能进行比较来完成的。所以,为了使它更清楚,这里是我所拥有的表的DDL:
CREATE TABLE [WorkerSkills](
[WorkerId] [bigint] NOT NULL,
[SkillName] [varchar](100) NOT NULL
) GO
CREATE TABLE [SkillCombinator](
[SetId] [int] NOT NULL,
[SkillCombinator] [varchar](5) NOT NULL
) GO
CREATE TABLE [RequiredSkills](
[SetId] [int] NOT NULL,
[SkillName] [varchar](100) NOT NULL
) GO
以下是示例数据:
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (1, 'A')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (1, 'B')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (1, 'C')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (2, 'D')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (2, 'X')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (3, 'E')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (4, 'A')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (4, 'B')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (4, 'H')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (4, 'I')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'A')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'B')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'C')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'E')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'G')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'H')
INSERT [WorkerSkills] ([WorkerId], [SkillName]) VALUES (5, 'I')
INSERT [SkillCombinator] ([SetId], [SkillCombinator]) VALUES (1, 'AND')
INSERT [SkillCombinator] ([SetId], [SkillCombinator]) VALUES (2, 'OR')
INSERT [SkillCombinator] ([SetId], [SkillCombinator]) VALUES (3, 'AND')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (1, 'A')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (1, 'B')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (1, 'C')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (2, 'D')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (2, 'E')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (2, 'F')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (3, 'G')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (3, 'H')
INSERT [RequiredSkills] ([SetId], [SkillName]) VALUES (3, 'I')
这意味着有3组,每组有3种技能定义。
set 1: A and B and C
set 2: D or E or F
set 3: G and H and I
有些工人具备以下技能:
worker 1: A, B, C
worker 2: D, X
worker 3: E
worker 4: A, B, H, I
worker 5: A, B, C, E, G, H, I
现在,问题是在Sql Server 2008中编写一个接受 WorkerId 和 SetCombinator 参数的函数,并返回一个值,指示Worker是否具备所有必需技能。
示例输入1:
WorkerId: 1
SetCombinator: OR
这意味着所有集合都应该具有 OR 组合子,即:
set 1: A and B and C
OR
set 2: D or E or F
OR
set 3: G and H and I
结果应为 true ,因为工人具有与第1组相对应的技能。
示例输入2:
WorkerId: 4
SetCombinator: OR
结果应为 false 。
示例输入3:
WorkerId: 1
SetCombinator: AND
这意味着所有集合都应该具有 AND 组合子,即:
set 1: A and B and C
AND
set 2: D or E or F
AND
set 3: G and H and I
结果应该是 false ,因为工人的技能只对应于第1组,而不是第2组和第3组。
示例输入4:
WorkerId: 5
SetCombinator: AND
结果应为 true ,因为工人具有与所有集合相对应的技能。
这个函数应该是什么样的想法?
更新:我忘了提到RequiredSkills表中的技能不是常量,它们经常会被修改,而且这些技能的数量也是动态的。因此,具有硬编码值的解决方案将无效。
答案 0 :(得分:0)
这是我到目前为止所拥有的。我希望你可以继续努力并进一步发展以适应你的问题。 我使用了按位逻辑 - 但我不是这方面的专家,这里可能还有其他人可以改进这一点。
DECLARE @WorkerID BIGINT = 1,
@LogicalCase BIT = 1, -- [0 = OR], [1 = AND]
@SkillScore INT = 0,
@isTrue BIT = 0
SELECT @SkillScore = SUM (
CASE WHEN SkillName = 'A' THEN 1
WHEN SkillName = 'B' THEN 2
WHEN SkillName = 'C' THEN 4
WHEN SkillName = 'D' THEN 8
WHEN SkillName = 'E' THEN 16
WHEN SkillName = 'F' THEN 32
WHEN SkillName = 'G' THEN 64
WHEN SkillName = 'H' THEN 128
WHEN SkillName = 'I' THEN 256
END
)
FROM WorkerSkills
WHERE WorkerID = @WorkerID
IF @LogicalCase = 0
BEGIN
IF (@SkillScore & 7 = 7) -- set 1: A and B and C
OR ( (@SkillScore & 8 = 8) OR (@SkillScore & 16 = 16) OR (@SkillScore & 32 = 32) ) -- OR set 2: D or E or F
OR (@SkillScore & 448 = 448) -- OR set 3: G and H and I
BEGIN
SET @isTrue = 1
END
END
IF @LogicalCase = 1
BEGIN
IF (@SkillScore & 7 = 7) -- set 1: A and B and C
AND ( (@SkillScore & 8 = 8) OR (@SkillScore & 16 = 16) OR (@SkillScore & 32 = 32) ) -- AND set 2: D or E or F
AND (@SkillScore & 448 = 448) -- AND set 3: G and H and I
BEGIN
SET @isTrue = 1
END
END
SELECT @isTrue
答案 1 :(得分:0)
可能不是最有效的,但它适用于任何数量的技能和组合:
declare @workerid int =5 -- input param
declare @setcombinator varchar(3) ='AND' -- input param
declare @skillsleft varchar(max)
declare @result varchar(10)
declare @getsets cursor
declare @set int
set @getsets = CURSOR FOR SELECT distinct SetId FROM SkillCombinator
OPEN @getsets
FETCH NEXT FROM @getsets INTO @set
-- set result by default
IF(@setcombinator='OR') set @result='FALSE' else set @result='TRUE'
WHILE @@FETCH_STATUS = 0
BEGIN -- compares each skillset against worker's and determine match or mismatch
if (select skillcombinator from skillcombinator where setid=@set) = 'AND'
BEGIN --needs all the skills in the set
SET @skillsleft=
(select count(*) from
(select skillname from RequiredSkills a
join SkillCombinator b on a.setid=b.setid
where a.setid=@set
except
select skillname from workerskills where workerid=@workerid) t)
-- override default depending on the logical combinations
if (@skillsleft = 0 and @setcombinator='OR') set @result='TRUE'
if (@skillsleft > 0 and @setcombinator='AND')set @result='FALSE'
END
if (select skillcombinator from skillcombinator where setid=@set) = 'OR'
BEGIN --needs at least one of the skills in the set
SET @skillsleft=
(select count(*) from
(select skillname from RequiredSkills a
join SkillCombinator b on a.setid=b.setid
where a.setid=@set
intersect
select skillname from workerskills where workerid=@workerid) t)
-- override default depending on the logical combinations
if (@skillsleft > 0 and @setcombinator='OR') set @result='TRUE'
if (@skillsleft = 0 and @setcombinator='AND') set @result='FALSE'
END
FETCH NEXT FROM @getsets INTO @set
END
select @result
CLOSE @getsets
DEALLOCATE @getsets
答案 2 :(得分:0)
好的,所以这是迄今为止我找到的最佳解决方案。
create function fnMatchedToSkillsSet
(
@WorkerId int,
@Condition varchar(3)
)
returns table
as
return (
with x as
(
select
sc.SetId,
nullif(case
when sc.SkillCombinator = 'AND' and count(distinct ws.SkillName) = count(*) then count(distinct ws.SkillName)
when sc.SkillCombinator = 'OR' then count(distinct ws.SkillName)
end, 0) as SkillsCount
from
dbo.SkillCombinator sc join
dbo.RequiredSkills rs on rs.SetId = sc.SetId left join
dbo.WorkerSkills ws on ws.WorkerId = @WorkerId and ws.SkillName = rs.SkillName
group by
sc.SetId, sc.SkillCombinator
)
select
case
when @Condition = 'AND' and count(SkillsCount) = (select count(*) from dbo.SkillCombinator) then 1
when @Condition = 'OR' and count(SkillsCount) > 0 then 1
else 0
end as Result
from
x
);