也许这个问题的标题不合适,但这里有解释:
我有以下表格:
只有5个福利代码:
因此,一名员工可以获得1至5项福利,但员工也可以获得任何福利。
我需要在查询中返回的是一个员工列表,其中包含相关权益的编码列,如下例所示:
因此,“好处”列是来自员工相关福利的编码列。
如果Peter已关联医疗和教育优势,则“优惠”列的编码值应如表“01001”所示,其中0表示无关联和1表示关联。
现在我正在使用follogin并且正在工作但需要很长时间才能处理,我确信有更好的方法和更快的方法:
SELECT emp.employee_id, emp.name, emp.lastname,
CASE WHEN lif.benefitcode IS NULL THEN '0' ELSE '1' END +
CASE WHEN med.benefitcode IS NULL THEN '0' ELSE '1' END +
CASE WHEN opt.benefitcode IS NULL THEN '0' ELSE '1' END +
CASE WHEN uni.benefitcode IS NULL THEN '0' ELSE '1' END +
CASE WHEN edu.benefitcode IS NULL THEN '0' ELSE '1' END as benefits
FROM employee emp
-- life
LEFT JOIN (
SELECT c.benefitcode, c.employee_id
FROM employee_benefit c
WHERE c.isactive = 1
and c.benefitcode = 'lf'
) lif on lif.employee_id = emp.employee_id
-- medical
LEFT JOIN (
SELECT c.benefitcode, c.employee_id
FROM employee_benefit c
WHERE c.isactive = 1
and c.benefitcode = 'md'
) med on med.employee_id = emp.employee_id
-- optical
LEFT JOIN (
SELECT c.benefitcode, c.employee_id
FROM employee_benefit c
WHERE c.isactive = 1
and c.benefitcode = 'op'
) opt on opt.employee_id = emp.employee_id
-- uniform
LEFT JOIN (
SELECT c.benefitcode, c.employee_id
FROM employee_benefit c
WHERE c.isactive = 1
and c.benefitcode = 'un'
) uni on uni.employee_id = emp.employee_id
-- education
LEFT JOIN (
SELECT c.benefitcode, c.employee_id
FROM employee_benefit c
WHERE c.isactive = 1
and c.benefitcode = 'ed'
) edu on edu.employee_id = emp.employee_id
关于什么是最佳表现的最佳方式的任何线索?
非常感谢。
答案 0 :(得分:1)
为什么不加入一个表格,将整数的好处编码(生命 - > 10000,医疗 - > 1000,......,教育 - > 1;然后
更新
select
EmployeeID,
right('0000' + convert(varchar(5),sum(map.value)),5)
from (
select value=10000, benefit = 'Lif' union all
select value= 1000, benefit = 'Med' union all
select value= 100, benefit = 'Uni' union all
select value= 10, benefit = 'Opt' union all
select value= 1, benefit = 'Edu'
) map
join
blah blah
group by EmployeeID
答案 1 :(得分:0)
首先请注意,此操作实际上是de-normalizes模型,如果是我的决定,我将保持规范化表格设计。我不确定这种情况的“压力”是什么,但我发现这种方法使得模型更难维护和使用。这种去规范化可能减慢了可能会在连接表上使用索引的查询。
话虽如此,一种方法是使用PIVOT,这是一个SQL Server(2005+)扩展。我做了一个example on sqlfiddle。该示例需要根据实际的表模式和权益值进行定制 - 在这种情况下,数据透视表位于链接(employee_benefit)表之上。请注意福利状态的预过滤器,以避免列(以及因此隐式分组)爬过PIVOT。
select pvt.*
from (
select emp, benefitcode
from benefits
where isactive = 1
) as b
pivot (
-- implicit group by on other columns!
count (benefitcode)
-- the set of all values (to turn into columns)
for benefitcode in ([lf], [md], [op])
) as pvt
create table benefits (
emp int,
isactive tinyint,
benefitcode varchar(10)
)
go
insert into benefits (emp, isactive, benefitcode)
values
(1, 0, 'lf'), (1, 1, 'md'), (1, 1, 'op'),
(2, 1, 'lf'),
(3, 1, 'lf'), (3, 1, 'md'), (3, 1, 'md')
go
EMP LF MD OP
1 0 1 1 -- excludes inactive LF for emp #1
2 1 0 0
3 1 2 0 -- counts multiple benefits
请注意,就像许多左连接一样,优势数据现在是一组固定值的面向列的。然后只需操作生成的查询中的数据(例如,在原始代码中完成,但检查> = 1)以构建所需的bit array值。
我不确定。但是,我的“初步预感”是,如果员工列被编入索引但查询效果不高,则查询可能会表现得更好;考虑到两种方法的反向inspect the query plan,它可能会表现得更糟,以了解
答案 2 :(得分:0)
我喜欢总结建议,但我会像这样内联:
Select
e.employee_id,
e.Name,
e.Lastname,
right('0000' + convert(varchar(5),sum(
case
when eb.benefitcode is null then 0
when eb.benefitcode = 'lf' then 10000
when eb.benefitcode = 'md' then 1000
when eb.benefitcode = 'op' then 100
when eb.benefitcode = 'un' then 10
when eb.benefitcode = 'ed' then 1
end )),5) benefits
from
Employee e
LEFT OUTER JOIN Employee_Benefit eb
on ( eb.Employee_id = e.Employee_id )
group by
e.employee_id,
e.Name,
e.Lastname
没有机会尝试语法,但这是一般的想法。
答案 3 :(得分:0)
WITH CTE (EMPID,EMPNAME,LASTNAME) AS (SELECT D.* FROM TABLENAME_EMP D WHERE D.EMPID=1), CTE2(BENEFITS) AS ((SELECT SUBSTRING((SELECT ''+ C.BENEFITS FROM (SELECT A.*,B.BEN_ID,CASE WHEN B.BEN_ID IS NULL THEN '0' ELSE '1' END BENEFITS FROM BEN_EMP b JOIN TABLENAME_EMP A ON A.empid=b.empid WHERE b.EMPID IN (1) AND B.ben_id IN (1,2,3,4,5)) C ORDER BY C.BENEFITS FOR XML PATH('')),1,200000) AS BENEFITS)) select * from cte,cte2