2015-01-01 2 views
6

У меня есть 2 строки, которые содержат только 0 и 1. Я хочу, чтобы строка результата побитовала ИЛИ их charcter по символу.Лучший способ для OR 2 строк 0,1

DECLARE @str1 nvarchar; 
DECLARE @str2 nvarchar; 
SET @str1= '11001100'; 
SET @str2= '00100110'; 

-- I want result to be : 11101110 

Размер строки является переменной. Я могу использовать цикл for и OR символы один за другим. но количество строк является переменной и размер их может быть более 1 миллиона ... Есть ли лучший способ, чем FOR цикл?

+3

Почему эти строки вместо двоичных данных? Вы используете байт для представления бит. В любом случае CLR, вероятно, будет наиболее эффективным способом. –

+0

Максимальная длина строки равна миллиону, или количество строк - миллион, а максимальная длина - короткая? – Beth

ответ

4

В идеале вы должны кодировать это в двоичной форме.

11001100 - это один байт 0xCC.

Хранение как varchar означает, что оно занимает 8 байт и объявлено как nvarchar, оно занимает 16 байт.

Вы также можете использовать CLR и побитовые операторы.

Ответ на вопрос, который вы задали, хотя с использованием функции CLR, вероятно, по-прежнему будет наиболее эффективным способом.

using System; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 

public partial class UserDefinedFunctions 
{ 
    [SqlFunction] 
    public static SqlString StringOr(SqlChars a, SqlChars b) 
    { 
     if (a.Length != b.Length) 
     { 
      throw new Exception("Strings should be the same length."); 
     } 

     char[] c = new char[a.Length]; 

     for(int i =0; i < a.Length; i++) 
     { 
      c[i] = (a[i] == '0' && b[i] == '0' ? '0' : '1'); 
     } 

     return (SqlString)(new SqlChars(c));   
    } 
} 

enter image description here

1

Попытка ниже

DECLARE @str1 nvarchar(10); 
DECLARE @str2 nvarchar(10); 
DECLARE @result nvarchar(10) = ''; 
declare @counter1 as int = 1; 
SET @str1= '11001100'; 
SET @str2= '00100110'; 
while @counter1 <= len(@str1) 
begin 
if (cast(substring(@str1,@counter1,1) as int) + cast(substring(@str2,@counter1,1) as int) >= 1) 
set @result += '1' 
else 
set @result += '0' 
set @counter1 += 1 
end 

print @result 
+1

Вы видели эту строку в вопросе ** Есть ли лучший способ, чем для цикла ** –

+1

Ops, я этого не видел. но он может находиться внутри определенной функции. – Mohammed

2

Варианта без использования цикла - чистый основой множественного подхода (с рекурсивным КТРОМ) и, следовательно, должен быть достаточно эффективными по сравнению с любым видом цикла. Вы можете использовать эту функцию, чтобы присоединиться или применить его к другим наборам данных (таблицы или представления)

-- function to split binary string to result-set 
alter function [dbo].[SplitStringToResultSet] (@value varchar(max), @size int) 
returns table 
as return 
with r as (
    select right(value, 1) [bit] 
    , left(value, len(value)-1) [value] 
    , 0 [pos] 
    from (select rtrim(cast(
     case 
      when len(@value) > @size then left(@value, @size) 
      when len(@value) < @size then @value + replicate('0', @size - len(@value)) 
      else @value 
    end as varchar(max))) [value]) as j 
union all 
select right(value, 1) 
, left(value, len(value)-1) 
, pos + 1 
from r where value > '') 

select cast([bit] as int) [bit], [pos] from r 

-- usage ------------------------------------------------- 
declare 
    @OR varchar(20) = '', 
    @AND varchar(20) = ''; 

select @OR = @OR + cast(n1.[bit] | n2.[bit] as varchar(1)) 
, @AND = @AND + cast(n1.[bit] & n2.[bit] as varchar(1)) 
-- XOR etc 
from [dbo].[SplitStringToResultSet] ('11001100', 8) n1 
full join [dbo].[SplitStringToResultSet] ('00100110', 8) as n2 on n1.[pos] = n2.[pos] 
order by n1.pos desc 

select @OR [OR], @AND [AND] 

Результат

OR   AND 
-------------------- 
11101110 00000100 
+1

Есть побитовые операторы OR и AND (|, &). Я думаю, вы можете использовать их вместо своих формул. '|' <=> 'n1 + n2 - n1 * n2'. '&' <=> 'n1 * n2'. –

+0

Большое спасибо за отзыв!реализовано :) –

+0

Поскольку вы все равно разбираете строку в функции, было бы логично переписать функцию, чтобы принимать два параметра Value1 и Value2 и OR внутри функции при их анализе. Таким образом, вы могли бы избежать «ПОЛНОГО ПРИСОЕДИНЕНИЯ». BTW, разбор строки с использованием рекурсивного CTE происходит медленнее, чем другие методы, например, используя таблицу Numbers: http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-2 –

1

Очень круто вопрос и решения. Добавить еще один с помощью XML: -convert Boths строки в XML, где каждый символ является узлом -make них таблица оценивается с битом и порядкового -join порядкового добавлением битами

DECLARE @str1 nvarchar(max) 
DECLARE @str2 nvarchar(max) 
declare @s1xml xml 
declare @s2xml xml 

SET @str1= '11001100' 
SET @str2= '00100110' 
set @s1xml =(select cast(replace(replace(@str1,'1','<n>1</n>'),'0','<n>0</n>') as xml)) 
set @s2xml =(select cast(replace(replace(@str2,'1','<n>1</n>'),'0','<n>0</n>') as xml)) 


select case when a.bit+b.bit = 0 then 0 else 1 end from 
(select n.value('.','int') bit, 
     n.value('for $i in . return count(../*[. << $i]) + 1', 'int') position 
from @s1xml.nodes('//n') as T1(n)) a 
join 
(select n.value('.','int') bit, 
     n.value('for $i in . return count(../*[. << $i]) + 1', 'int') position 
from @s2xml.nodes('//n') as T2(n)) b 
ON a.position=b.position 
for xml path('') 
0

Если предположить, что максимальная длина строки не миллион, а гораздо меньшее число, я бы использовал таблицу поиска с двумя столбцами и строками длины строки 2^max с строками char и соответствующими двоичными значениями. Затем вы можете присоединить две строки к двум экземплярам таблицы поиска и использовать побитовые функции OR для результатов.

select bitstr1, bitstr2, b1.bin, b2.bin, b1.bin | b2.bin as OR_result 
from 
tblMillion inner join 
tblLkpBin b1 on 
bitstr1 = b1.str inner join 
tblLkpBin b2 on 
bitstr2 = b2.str 
Смежные вопросы