T-SQL - 值与列表中的至少一个项不匹配

时间:2014-07-24 21:18:07

标签: sql-server tsql select

我有一个包含多个列的MS SQL表,每个列用于不同的员工角色,每个列都有一个相应的列,用于指示该角色中的当前员工是处于活动状态,休假,终止等。由于依赖外部数据来源,这些字段并没有真正规范化。

我希望运行一个查询来返回至少有一个的'活跃的所有行。列等于' ACTIVE'。除Active之外还有几个可能的值。

我知道其中一个较长的方法是

SELECT * FROM MYTABLE
WHERE IsActive1 <> 'ACTIVE' OR
      IsActive2 <> 'ACTIVE' OR
      IsActive3 <> 'ACTIVE' OR
      IsActive4 <> 'ACTIVE' OR
... etc

只是想知道是否有更短的方式,可能更有效的方式来做到这一点。我已经看到了很多解决方案,可以在多个列中找到匹配项,但不是一个用于查找不匹配项的解决方案。

2 个答案:

答案 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,...列拆分为子表中的不同行。然后,您可以在该表上执行单个筛选索引。