2017-07-06 49 views
1

我正在使用Access 2010中的一些數據在SQL Server上工作,我沒有靈活性來更改,只能查詢。每個單獨的實體都有一個ID,並且可能有一個沒有特定最大或最小條目的屬性列表。創建此數據集的人所創建的解決方案是創建37個不同的屬性列集。對於每個屬性,有4列(儘管只有2列是有用的)。實際上,有148列表示可能有37個項目,雖然大多數列3或4以後的列都是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 |

什麼是對這個查詢,這樣,如果有人想抄本= 1(X爲任意數字),查詢返回的結果,即使該行有代碼1的最佳方式= 1或Code37 = 1。我認爲這樣做是這樣的:

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

但是,這看起來很醜陋,大概就像乾涸的山洪一樣。如果我想要同時定位屬性和代碼,這將變得特別可怕,我可能會這樣做。我簡單地查看了CASE,希望我能想到一種方法來使用它迭代並將第一個空值的值帶回給我,但是我的草稿沒有太大的意義,並且很亂嵌套。

有關如何通過上面建議的真正難看的方法來解決這些問題的任何想法?

+0

你能做到直通查詢?在列中使用COALESCE關鍵字以相反的順序獲得列列表中的第一個非空值 – Jeremy

+0

我可以做轉發,是的。那麼讓我快速看一下。 –

+0

好的,這樣就可以接近我所需要的了。我想在此之後執行的其中一個步驟是能夠返回所有不爲空的值,這樣可以節省一些打字量。 我也希望能夠匹配特定值,這意味着我需要每次寫出表達式來合併,因爲「NOT NULL」不夠有意義。然後,我馬上回到開始使用OR語句的地方。 –

回答

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) 

在性能方面,它可能會以更快的速度 unpivot的數據,但讓優化器使用下面的邏輯與簡單的布爾comparisions

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) 
+0

我大致瞭解你要去哪裏,這很有幫助。就執行情況而言,這會比OR語句組合的37個條件更好嗎?我擔心在一個已經很大的數據庫上執行這樣複雜的操作會嚴重影響我的性能。我的代碼主要在後臺運行,用戶輸入將定義正在搜索的代碼和/或屬性,因此最終用戶的性能是最重要的。不幸的是,下載本地修改的表格副本也將失敗目的,因爲此表每月更新一次。 –

+0

那麼,不可能判斷哪個更好......這取決於你的結構,索引等等。唯一真正可以告訴的方法是在測試系統上或者在下班時間或者其他方面進行測試。如果你運行它並且需要超過幾秒鐘的時間(或者你的閾值是什麼),那麼就殺掉查詢並嘗試另一種方式。說實話,一個大的布爾語句可能是最快的,儘管你的查詢將會很長,它可能會表現良好。我會在底部更新。 – scsimon

+0

@AndrewMcPheron更新了答案。優化器幾乎肯定會找到最快的最後一個查詢。您可以將這兩個參數中的任何一個參數設置爲null,也可以不設置爲null – scsimon