我有一个包含多个列的MS SQL表,每个列用于不同的员工角色,每个列都有一个相应的列,用于指示该角色中的当前员工是处于活动状态,休假,终止等。由于依赖外部数据来源,这些字段并没有真正规范化。
我希望运行一个查询来返回至少有一个的'活跃的所有行。列不等于' ACTIVE'。除Active之外还有几个可能的值。
我知道其中一个较长的方法是
SELECT * FROM MYTABLE
WHERE IsActive1 <> 'ACTIVE' OR
IsActive2 <> 'ACTIVE' OR
IsActive3 <> 'ACTIVE' OR
IsActive4 <> 'ACTIVE' OR
... etc
只是想知道是否有更短的方式,可能更有效的方式来做到这一点。我已经看到了很多解决方案,可以在多个列中找到匹配项,但不是一个用于查找不匹配项的解决方案。
答案 0 :(得分:2)
我不知道这更优雅,但你可以这样做:
where replace(IsActive1 + IsActive2 + IsActive3 + . . .,
'ACTIVE', '') <> ''
请注意,如果值可能是NULL
,那么您需要将其替换为其他内容。此外,这假设字符串本身不为空。
编辑:
如果您想有效地执行此操作和希望代码看起来不错,请添加计算列并在该列上构建索引:
alter table mytable
add IsAllActive as (case when IsActive1 = 'ACTIVE' and
IsActive2 = 'ACTIVE' and
. . .
then 'ACTIVE'
else 'INACTIVE'
end);
create index mytable_IsAllActive on mytable(IsAllActive);
您可能还想将其他相关列添加到索引中。
答案 1 :(得分:0)
尝试使用过滤索引,这在WHERE
子句中包含的内容非常有限:
--simulate your existing table
create table Test (RowID int identity(1,1) primary key
,c1 varchar(10), c2 varchar(10),c3 varchar(10),c4 varchar(10)
)
go
--simulate your existing data
INSERT INTO Test VALUES ('ACTIVE','ACTIVE','ACTIVE','ACTIVE') --1
, ('ACTIVE','ACTIVE','ACTIVE','ACTIVE') --2
, ('ACTIVE','ACTIVE','ACTIVE','ACTIVE') --3
, ('INACTIVE','ACTIVE','ACTIVE','ACTIVE') --4 <Inactive
, ('ACTIVE','INACTIVE','ACTIVE','ACTIVE') --5 <Inactive
, ('ACTIVE','ACTIVE','INACTIVE','ACTIVE') --6 <Inactive
, ('ACTIVE','ACTIVE','ACTIVE','INACTIVE') --7 <Inactive
, ('INACTIVE','ACTIVE','ACTIVE','INACTIVE') --8 <Inactive
, ('INACTIVE','ACTIVE','INACTIVE','INACTIVE') --9 <Inactive
, ('INACTIVE','INACTIVE','INACTIVE','INACTIVE')--10<Inactive
go
--what you need to add to your existing table
CREATE NONCLUSTERED INDEX fIX_Test_c1 ON Test(c1) WHERE C1 !='ACTIVE'
CREATE NONCLUSTERED INDEX fIX_Test_c2 ON Test(c2) WHERE C2 !='ACTIVE'
CREATE NONCLUSTERED INDEX fIX_Test_c3 ON Test(c3) WHERE C3 !='ACTIVE'
CREATE NONCLUSTERED INDEX fIX_Test_c4 ON Test(c4) WHERE C4 !='ACTIVE'
--your query o get the data
SELECT * FROM Test WHERE c1 !='ACTIVE'
UNION SELECT * FROM Test WHERE c2 !='ACTIVE'
UNION SELECT * FROM Test WHERE c3 !='ACTIVE'
UNION SELECT * FROM Test WHERE c4 !='ACTIVE'
您可以尝试使用索引的持久计算列:
ALTER TABLE Test ADD C_Summary AS (LEFT(ISNULL(c1,'Z'),1)+LEFT(ISNULL(c1,'Z'),1)+LEFT(ISNULL(c1,'Z'),1)+LEFT(ISNULL(c1,'Z'),1))
go
CREATE NONCLUSTERED INDEX fIX_Test_C_Summary ON Test(C_Summary)
go
select * from test WHERE C_Summary !='AAAA'
您必须在数据上尝试这些(和其他变体),这可能会扭曲索引的使用。此外,您可能希望尝试更改表设计,将所有C1,C2,C3,C4,...列拆分为子表中的不同行。然后,您可以在该表上执行单个筛选索引。