2013-05-06 12 views
7

Mam wartość bitmask przechowywane jako int w sql. Chciałbym zmienić tę wartość na rozdzieloną przecinkami listę wartości zawartych w wartości maski bitowej.W SQL, w jaki sposób można podzielić wartości w masce bitmask razem na przecinek rozdzielany przecinkami

Tak więc, na przykład, wyniki mogą wyglądać tak:

id name  bitMaskValue values 
---------------------------------------- 
1 Bob  5    1,4 
2 Mary  13    1,4,8 
3 Stan  11    1,2,8 

Czy istnieje sposób do osiągnięcia tego celu w sql?

Jest to SQL Server 2008.

+1

To pytanie nie wykazuje żadnego wysiłku badawczego. Ważne jest, aby ** wykonać zadanie domowe **. Powiedz nam, co znalazłeś i dlaczego *** nie spełnia Twoich potrzeb. To pokazuje, że poświęciłeś czas, aby spróbować pomóc sobie, to ratuje nas od powtarzania oczywistych odpowiedzi, a przede wszystkim pomaga ci uzyskać bardziej szczegółową i trafną odpowiedź. [FAQ] (http://stackoverflow.com/questions/how-to-ask). – Kermit

+3

Tylko FYI, naprawdę nadużywasz swojego RDBMS. Bazy danych mają działać * naprawdę dobrze * z kluczami obcymi. Mam nadzieję, że przed dodaniem maski bitowej do swoich rekordów masz dość specyficzne wymagania, a nie normalizacją danych i użyciem typowej tabeli skrzyżowań. – meagar

+0

Całkowicie się z tobą zgadzam @meagar. W moim przypadku mam niektóre starsze dane (bitMaskValue), które właśnie próbuję znormalizować i wypchnąć do innego źródła, które ma wartości rozdzielane przecinkami. Pomyślałem, że to interesująca zagadka i odkąd nie znalazłem żadnych rozwiązań SQL tylko przez Google lub SO, zastanawiałem się, jakie dobre rozwiązania mogą mieć ludzie. – Jimtronic

Odpowiedz

1
declare @I integer = 2117 

Declare @v varChar(32) = '' 
Declare @Bit tinyInt = 0 
while @I > 0 Begin 
Set @v += case @I %2 WHen 1 Then str(@bit,2,1) + ',' else '' End 
Set @Bit += 1 
Set @i /= 2 
End 
Select case When len(@v) > 0 Then left(@v, len(@v) -1) else '' End 
+0

Dzięki. Stworzyłem dla tego funkcję i działało dobrze. Zmieniłem wyjście z 'str (@ bit, 2,1)' na 'str (power (2, @ bit), 2,1)', aby dopasować to, czego potrzebowałem. – Jimtronic

+0

btw, całkowicie zgadzam się z komentarzem @ meagera do twojego pytania. To nie jest właściwe/dobre wykorzystanie serwera baz danych ... –

3

To powinno działać:

SELECT id, name, bitMaskValue, 
    SUBSTRING(
      CASE WHEN bitMaskValue & 1 = 1 THEN ',1' ELSE '' END 
      + CASE WHEN bitMaskValue & 2 = 2 THEN ',2' ELSE '' END 
      + CASE WHEN bitMaskValue & 4 = 4 THEN ',4' ELSE '' END 
      + CASE WHEN bitMaskValue & 8 = 8 THEN ',8' ELSE '' END 
     , 2, 64) As [values] 
FROM yourTable 
+0

Dokładnie tego szukałem! Dziękuję bardzo. – CowboyBebop

1

CTE + XPATH way:

set nocount on 

declare @t as table(id int, name varchar(100), bitMaskValue int) 

insert into @t(id, name, bitMaskValue) values(1,'Bob',5) 
insert into @t(id, name, bitMaskValue) values(2,'Mary',13) 
insert into @t(id, name, bitMaskValue) values(3,'Stan',11) 

;with cte(num) as 
(
select 1 
union all 
select num*2 
from cte 
) 
select 
    id, 
    name, 
    bitMaskValue, 
    stuff((
     select cast((
     select isBitSet 
     from 
     (
      select top 31 num, 
         case 
          when bitMaskValue & num = num then ',' + cast(num as varchar(10)) 
          else null 
         end isBitSet 
      from cte 
     ) tmp 
     where isBitSet is not null 
     for xml path('')) as xml).value('.', 'VARCHAR(max)') 
    ), 1, 1, '') bitSet 
from @t 
Powiązane problemy