2016-04-22 33 views
-1

我有一個很多列(比如說200)的表,它們都是布爾型的。我想知道其中哪些至少有一個記錄設置爲true。我想出了以下查詢工作正常:檢查很多colums至少有一個'真'

SELECT sum(Case When [column1] = 1 Then 1 Else 0 End) as column1, 
sum(Case When [column2] = 1 Then 1 Else 0 End) as column2, sum(Case 
When [column3] = 1 Then 1 Else 0 End) as column3, FROM [tablename]; 

它會返回列的'真'的行數。但是,這比我需要的信息更多,因此可能需要更昂貴的查詢。查詢不斷掃描所有記錄的所有字段,即使這不是必需的。

+0

行有列,而不是相反。如上所述,你的問題很混亂。你有200行,你想知道是否至少有一列至少有一列是1?或者你的每行都有200列(我見過瘋狂的東西),並且你想知道,對於每一行,是否至少有一列是1? –

+0

可以做一些類似'select * from tablename where 1 in(column1,column2,column3)' – JamieD77

+0

您可以嘗試'SELECT MAX(column1)作爲column1,... FROM [tablename]'。這聽起來像你想知道每列是否有任何行是真的。如果是這種情況,那麼如果該列中的任何行爲真,MAX將返回1。 – Roberto

回答

0

我只是學會了一些校驗和(*),可能是有用的。試試下面的代碼:

DECLARE @T TABLE (
b1 bit 
,b2 bit 
,b3 bit 
); 

DECLARE @T2 TABLE (
b1 bit 
,b2 bit 
,b3 bit 
,b4 bit 
,b5 bit 
); 

INSERT INTO @T VALUES (0,0,0),(1,1,1); 
INSERT INTO @T2 VALUES (0,0,0,0,0),(1,1,1,1,1); 

SELECT CHECKSUM(*) FROM @T; 
SELECT CHECKSUM(*) FROM @T2; 

你會從結果,無論有多少列在一排,看看他們都位列爲0的值,校驗和(*)的結果總是0.

這意味着您可以在查詢中使用WHERE CHECKSUM(*)<>0以節省引擎所有值爲0的行的總和問題。可能會提高性能。

即使它不,它是一個很好的知道。

編輯:

你可以在每列上做一個EXISTS()函數。我知道EXISTS()函數在找到一個存在的值時會停止掃描。如果您的行數多於列數,則可能會更高效。如果您的列數多於行數,那麼在每列上使用SUM()的當前查詢可能是您可以做的最快的事情。

+0

即使當所有列爲0時'CHECKSUM'總是0,如果任何列不是0,它並不一定是0。您必須深入研究實現。 (嚴格測試所有2^200種可能的組合,恐怕......)例如,在所有列上執行「XOR」的微不足道的校驗和(這不是實際的校驗和,而是與我相關)在每個偶數個1上都是0,即使它在0上也是0。 –

+0

我不知道XOR在TSQL語法方面會是什麼樣子,但是如果您使用*作爲CHECKSUM的唯一參數,那麼可以使用該行中的所有列。我不是要測試每一個200位列的組合,你是對的,但是如果你可以找到一種方法來獲得一個CHECKSUM(*)爲零的方式,當任何一列的值爲1.這意味着具有不同值的兩行將具有相同的CHECKSUM,這將破壞CHECKSUM的目的,並且,對於我的(被公認有限的)理解,這是不可能的。 –

+0

T-SQL中的'XOR'是'^'。但我並不真正關心你是否願意消化頭飾 - 我不會在任何個人開發人員的想象力缺乏的情況下認同任何解決方案的正確性。 「CHECKSUM」的碰撞特性非常糟糕;我確實沒有太多的麻煩,認爲即使有足夠的輸出位,也可能存在無法正確分配輸入位的列組合。將尋找例子的負擔轉移給我是很好的,但如果你不介意的話,我也不會去檢查所有的組合。 :-) –

0

如果你實際上在一個表上有200列/布爾值,那麼類似下面的東西應該可以工作。

SELECT CASE WHEN column1 + column2 + column3 + ... + column200 >= 1 THEN 'Something was true for this record' ELSE NULL END AS My_Big_Field_Test 
FROM [TableName]; 
+0

大於等於1(> = 1) –

+0

這是個好主意。更新。雖然......基於對查詢的解釋和對問題的評論,但這可能與OP的需求不匹配。 :/ – JNevill

+0

你必須在每個地方都加上CAST(column1 AS INT),因爲不允許在'BIT'字段上進行算術運算。 (當我談論「布爾」時,我假定OP是什麼意思)。 –

0

如果你只是想知道在最後一個布爾型字段中的行,你將需要測試它們中的每一個。

像這樣的東西(也許):

SELECT ROW.* 
FROM TABLE ROW 
WHERE ROW.COLUMN_1 = 1 
OR ROW.COLUMN_2 = 1 
OR ROW.COLUMN_3 = 1 
OR ... 
OR ROW.COLUMN_N = 1; 
+0

不,這不是我想知道的。我想知道對於該列至少有一行值爲'true'的所有列名稱。 –

0

我不是在我的機器面前,但你也可以嘗試按位或操作:

SELECT * FROM [table name] WHERE column1 | column2 | column3 = 1 

的OR答案亞瑟是其他建議,我會提供。嘗試一些不同的建議並查看查詢計劃。還要看看磁盤讀取和CPU使用情況。 (SET STATISTICS IO ON和SET STATISTICS TIME ON)。

見任何方法給出了慾望的結果和最佳的性能......然後讓我們知道:-)

+0

這將返回至少一個列值爲true的所有行。我希望所有列名至少有一列的列值爲真的行。 –

0

可以使用形式的查詢

SELECT 
    CASE WHEN EXISTS (SELECT * FROM [Table] WHERE [Column1] = 1) THEN 0 ELSE 1 END AS 'Column1', 
    CASE WHEN EXISTS (SELECT * FROM [Table] WHERE [Column2] = 1) THEN 0 ELSE 1 END AS 'Column2', 
    ... 

這樣做的效率至關重要取決於你的桌子的稀疏程度。如果列中每一行的值都爲0,則除非索引就位,否則任何搜索1值的查詢都需要全表掃描。此場景(數百萬行和數百列)的一個非常好的選擇是columnstore index。這些從SQL Server 2012開始支持;從SQL Server 2014開始,它們不會導致表是隻讀的(這是它們採用的主要障礙)。

對於一個列存儲索引,每個子查詢都應該需要一個固定時間,查詢作爲一個整體(事實上,包含數百個列,這個查詢會變得非常大以至於您可能會遇到輸入緩衝區並需要將其分解成更小的查詢)。如果沒有索引,只要表格不是稀疏的,該查詢仍然可以有效 - 如果它「快速」運行到具有1值的行,則停止。

+0

感謝您的信息。令人遺憾的是,在這方面,桌子是'稀疏'的。我們正在幾個月內遷移到一個內存表中,並有一個列存儲索引。 –

相關問題