Выполнение поразрядной суммы

Как часть сложного агрегата, я хочу знать поразрядную сумму некоторых данных, т.е. если у меня есть строки со значениями 1,1,1,2,2,8, поразрядная сумма равна 11. В этом случае значения все точные мощности двух (одиночные биты), поэтому я могу взломать его, группируя и суммируя по группам (очевидно, этот пример немного замучен по сравнению с реальным запросом):

select SUM(y.test)
from (
    select x.test
    from ( -- garbage test data
        select 1 as [test]
        union all select 1
        union all select 1
        union all select 2
        union all select 2
        union all select 8) x
group by x.test) y

но есть ли чистый способ выполнить побитную сумму в [T] SQL?

Ответ 1

Если все ваши тестовые значения являются одиночными битами, как в вашем примере (1, 2, 8), просто используйте SUM(DISTINCT col) в своем запросе.

Надеюсь, что это поможет.

(для справки: http://msdn.microsoft.com/en-us/library/ms187810.aspx)

Ответ 2

Его немного запутанный, но это делает то, что вам нужно (обратите внимание, что в iive включен бит до 128, вам может потребоваться больше, или, возможно, не нужно идти выше 8).

with data(i)
AS
(
    select 1 
        union all select 1
        union all select 1
        union all select 2
        union all select 2
        union all select 8
)
SELECT MAX(i & 1) +
MAX(i & 2) +
MAX(i & 4) +
MAX(i & 8) +
MAX(i & 16) +
MAX(i & 32) +
MAX(i & 64) +
MAX(i & 128)
from data

который, очевидно, может быть преобразован в UDF, если вы этого пожелаете.

Ответ 3

У вас есть оператор | который выполняет побитовое или для 2 операндов. Вы можете решить свою проблему с помощью курсора и этого оператора.

Изменить да, я перепутал и/или исправил.

Ответ 4

Для одиночных бит SUM (DISTINCT col) лучший ответ, но для нескольких бит, таких как 3 (= 1 | 2), это не работает, и лучший и быстрый ответ будет таким:

SELECT SUM (DISTINCT X.Text и T.B) FROM X cross join (значения (1), (2), (4), (8), (16), (32), (64), (128), (256), (512)) T (B)