2011-05-06 38 views
2

我在查找快速計算BINARY(1024)字段的漢明重量/總體數/「1位數」的方法。 MySQL有一個BIT_COUNT函數可以做那樣的事情。我無法在T-SQL中找到類似的功能?T-SQL中的漢明體重/人口數

或者你會建議將二進制數據存儲在另一種類型的字段中?

如果你不知道我在說什麼,這裏是Wikipedia article about the hamming weight

+0

http://weblogs.sqlteam.com/jeffs/archive/2007/05/09/60197.aspx – Lamak 2011-05-06 20:06:07

+0

這可能是一個CLR函數的工作。此外,您可能已考慮過這一點,但如果您對唯一二進制值的計數爲數千乃至數百萬,則可以創建一個表以在第一次計算每個值時爲其存儲彈出窗口。或者將它存儲在主表中,因爲您只需要一個'SMALLINT'。 – 2011-05-07 14:18:56

回答

4

你可以使用一個輔助表預先計算的漢明權重小的數字,如字節,那麼相應的分割值,加入到幫助表,並得到部分海明權重的總和作爲值的海明重量:

-- define Hamming weight helper table 
DECLARE @hwtally TABLE (byte tinyint, hw int); 
INSERT INTO @hwtally (byte, hw) VALUES (0, 0); 
INSERT INTO @hwtally (byte, hw) SELECT 1 - byte, 1 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 3 - byte, 2 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 7 - byte, 3 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 15 - byte, 4 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 31 - byte, 5 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 63 - byte, 6 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 127 - byte, 7 - hw FROM @hwtally; 
INSERT INTO @hwtally (byte, hw) SELECT 255 - byte, 8 - hw FROM @hwtally; 

-- calculate 
WITH split AS (
    SELECT SUBSTRING(@value, number, 1) AS byte 
    FROM master.dbo.spt_values 
    WHERE type = 'P' AND number BETWEEN 1 AND LEN(@value) 
) 
SELECT 
    Value = @value, 
    HammingWeight = SUM(t.hw) 
FROM split s 
    INNER JOIN @hwtally t ON s.byte = t.byte 
+0

完美!謝謝。之前不知道spt_values。 – Simon 2011-05-09 11:42:25

+0

@Simon:以下是一些有用的信息:http://stackoverflow.com/questions/4273723/what-is-the-purpose-of-system-table-table-master-spt-values-and-what-是最MEA – 2011-05-09 11:54:23

0

沒有找到特別是約漢明權重東西,但這裏有一個漢明距離:

create function HamDist(@value1 char(8000), @value2 char(8000)) 
returns int 
as 
begin 
    declare @distance int 
    declare @i int 
    declare @len int 

    select @distance = 0, 
      @i =1, 
      @len = case when len(@value1) > len(@value2) 
         then len(@value1) 
         else len(@value2) end 

    if (@value1 is null) or (@value2 is null) 
     return null 

    while (@i <= @len) 
     select @distance = @distance + 
          case when substring(@value1,@i,1) != substring(@value2,@i,1) 
           then 1 
           else 0 end, 
       @i = @i +1 

    return @distance 
end 

這種計算兩個值之間的漢明距離。單個值的漢明權重將是該值與零值數組之間的漢明距離。

+0

感謝您的回覆。這與@Lamak已經發布的算法是一樣的。然而,實施並不快。我必須首先將字段轉換爲CHAR(類似於http://support.microsoft.com/kb/104829),然後調用此例程。是不是有至少按字節計算漢明距離的東西? – Simon 2011-05-06 20:15:33

0

我找不到一個好辦法。最後,我計算了Java中的漢明重量,並定期更新數據庫中的位數。

1

當你使用較小的值(類似於16位最大值)時,使用SQL Server最有效的方法是使用一個表,所有結果都計算出來並使用連接。

我已經加快查詢從30秒到0秒通過做這樣的事情在一個查詢應該計算在17'000行的4位值的漢明權重。

WITH HammingWeightHelper AS (
     SELECT x, Fx 
     FROM (VALUES(0,0),(1,1),(2,1),(3,2), 
        (4,1),(5,2),(6,2),(7,3), 
        (8,1),(9,2),(10,2),(11,3), 
        (12,2),(13,3),(14,3),(15,4)) AS HammingWeight(x, Fx) 
    ) 
SELECT HammingWeight.Fx As HammingWeight, SomeTable.Value As bitField 
FROM SomeTable INNER JOIN 
     HammingWeightHelper ON HammingWeightHelper.x = SomeTable.Value 

當然這是一個醜陋的解決方案,它可能不適合很長的位字段。