迭代表列直到空值

时间:2017-07-06 17:19:29

标签: sql sql-server loops ms-access ms-access-2010

我通过Access 2010处理SQL Server上的一些数据,我无法灵活地更改,只能查询。每个单独的实体都获得一个ID,并且可能有一个跟随它的属性列表,没有特定的最大或最小条目。创建此数据集的人员的解决方案是创建37个不同的列属性集。对于每个属性,有4列(尽管只有2列有用)。实际上,有148列代表可能有37个项目,但过去组3或4的大多数列都是NULL。虽然有一些一致性 - 值首先转到第一列组。只要任何列具有空值,就可以假定其后的每个列也为空。如果第一列为null,则它没有属性。数据看起来有点像这样:

| ID | Attr1 | Code1 | Attr2 | Code2 | Attr3 | Code3 | |----|-------|-------|--------|--------|--------|--------| | 1 | Foo | 2 | Bar | 1 | (null) | (null) | | 2 | Bar | 2 | (null) | (null) | (null) | (null) | | 3 | Bar | 1 | Foo | 1 | Bar | 2 |

查询此问题的最佳方法是,如果有人想要CodeX = 1(X是任意数字),即使该行具有Code1 = 1或Code37 = 1,查询也会返回结果。我考虑做过这样的事情:

A.Mod1=1
Or A.Mod2=1
Or A.Mod3=1
Or A.Mod4=1
...

但这看起来很可怕,并且就像暴洪一样干涸。如果我想要同时定位属性和代码,那将变得特别可怕,我可能会这样做。我简短地查看了CASE,希望我能想到一种方法来使用它来迭代并将我的第一个空值的值带回来,但是我的草稿并没有多大意义,而且一样混乱/重度嵌套。

除了上面建议的那种非常丑陋的方法之外,有关如何解决这些问题的任何想法吗?

1 个答案:

答案 0 :(得分:0)

以下两种方法来取消您的数据。这样做,您只需为参数添加where子句即可。即只需将where code = 1添加到第一个查询,或where codes = 1添加到第二个查询。如有必要,您也可以将其重新调整,但这会将其标准化为一吨。正如你所说,你可以通过一个疯狂的长CASE声明来做到这一点,但它干燥而冗长。

declare @table table(ID int, Attr1 varchar(16), Code1 varchar(16),Attr2 varchar(16), Code2 varchar(16), Attr3 varchar(16), Code3 varchar(16))
insert into @table
values
(1,'Foo',2,'Bar',1,NULL,NULL),
(2,'Bar',2,NULL,NULL,NULL,NULL),
(3,'Bar',1,'Foo',1,'Bar',2)

select
    t.ID, 
    c.Attribute,
    c.Code
from @table t
cross apply (
            select Attr1, Code1 union all
            select Attr2, Code2 union all
            select Attr3, Code3 
            ) c (Attribute, Code)
where
    Attribute is not null


select
    ID,
    Attributes,
    Codes
from(
     select ID, Attr1, Code1, Attr2, Code2, Attr3, Code3 
     from @table) main
unpivot
(Attributes for Attribute in (Attr1, Attr2, Attr3)) attr
unpivot
(Codes for Code in (Code1, Code2, Code3)) cod
where
    right(Attribute,1) = right(Code,1)

性能方面, NOT 对数据进行取消操作可能会更快,但让优化器使用下面的逻辑进行简单的布尔比较

declare @Code int = 2
declare @Attr varchar(64) = null

select
    t.*
from @table t
where
    (Code1 = @Code or
     Code2 = @Code or
     Code3 = @Code or
     @Code is null)
     and
     (Attr1 = @Attr or
      Attr2 = @Attr or
      Attr3 = @Attr or
      @Attr is null)