#title 문자열 Bit 연산 문제 [[TableOfContents]] ==== 문제 ==== 오늘 데브피아에 재미있는 질문이 올라왔다. 기수변환과 Bit연산에 관련된 문제로 DBMS에서는 다소 취약한 부분이기 때문에 문제를 풀어보았다. 질문은 다음과 같다. (원문: http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=41&MAEULNo=17&no=4619&ref=4619) ||안녕하세요 MS SQL 에서.. '1001' , '0101' 이런 식의로 4자리 문자열로 된 2진수 형태의 문자를... OR 비트 연산을 해서 새로운 4자리 문자열을 만들어 내야합니다. 예를 들어 문자 '1001' 과 '0101' 를 OR 비트 연산하여.. '1101' 이라는 문자를 뽑아내야 하는거죠.. 쿼리를 못짜겠어서.. 부탁드립니다.|| {{{* 질문에 답변이 달렸을 것이다. 다른 사람의 솔루션을 보는 것은 꽤 도움이 된다. 꼭 클릭질해서 다른 솔루션을 보기 바란다.}}} ==== 풀이 ==== {{{ /* drop table #temp create table #temp(seq int, a varchar(30), b varchar(30)) insert #temp values(1, '1001' , '0101') insert #temp values(2, '10011' , '01011') */ with dumy(num) as ( select 0 num union all select num + 1 from dumy where num + 1 <= 30 ), rs (seq, a, b, rs) as ( select a.seq , a.a , a.b , b.rs from #temp a cross apply ( select case when '1' in (substring(a.a, num+1, 1), substring(a.b, num+1, 1)) then '1' else '0' end rs from dumy where num <= case when len(a.a) > len(a.b) then len(a.a) else len(a.b) end - 1 ) b ) select distinct seq , a , b , (select cast(rs as varchar(100)) as 'text()' from rs where a.seq = seq for xml path('')) [a | b] from rs a }}} ==== 복잡해진 이유가 뭘까? ==== 풀이를 보면 좀 복잡하다는 생각을 들 것이다. 필자가 보기에는 더 이상 단순하게는 안 된다. 왜냐하면 문제 자체가 DBMS의 특성을 전혀 고려하지 않았기 때문이다. 어플리케이션의 Bit연산은 정말 쉽다. 물론 일반적으로 DBMS의 Bit연산도 쉽다. '1101'과 같은 문자열이 아니라 13이라는 숫자를 그저 Bit연산을 했다면 복잡하지도 않을 뿐더러 비용도 몇 천배(어쩌면 몇 만배 이상) 절약할 수 있었을 것이다. 즉, 다음과 같을 것이다. ||2진수||10진수|| ||1101||13|| ||0101||5|| 즉, 13, 5와 같은 형식이면 SQL Server에서 OR Bit연산은 다음과 같을 것이다. {{{ select 13|5 }}} 결국은 또 설계[* 인터페이스 설계] 문제다. 두 설계의 비용(유지보수 포함)을 비교하면? 아마도 수 억배에 다달을 것이다. ==== 다른 풀이 ==== {{{ --drop table #temp create table #temp(id int, col1 varchar(30), col2 varchar(30)) insert #temp values(1, '1001' , '0101') insert #temp values(2, '10011' , '01011') ;with dummy(seq) as ( select 1 seq union all select seq + 1 from dummy where seq + 1 <= 30 ), result as ( select a.id , a.col1 , a.col2 , sign(convert(tinyint, substring(col1, seq, 1)) + substring(col2, seq, 1)) rs from #temp a cross join dummy b where b.seq <= len(a.col1) ) select id , x [col1 | col2] from #temp a cross apply ( select ( select cast(rs as varchar(100)) as 'text()' from result where a.id = id for xml path('')) x ) b }}}