OR 2字符串0,1的最佳方法

时间:2015-01-01 10:02:01

标签: sql-server bit

我有2个字符串,只包含0和1.我想要一个按位的结果字符串或者按字符逐个字符。

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

-- I want result to be : 11101110

字符串的大小是可变的。我可以逐个使用for循环和OR字符。但是字符串的数量是可变的,它们的大小可能超过100万......有没有比FOR循环更好的方法?

5 个答案:

答案 0 :(得分: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 :(得分:2)

Variant不使用循环 - 纯粹的基于集合的方法(使用递归CTE),因此与任何类型的循环相比应该非常有效。 您可以使用此函数将其加入或应用于其他数据集(表或视图)

-- 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

答案 2 :(得分: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

答案 3 :(得分:1)

非常酷的问题和解决方案。我使用xml添加另一个: - 将字符串转换为xml,其中每个char都是一个节点 - 使用bit和ordinal来表示它们的表 -join by ordinal added bits

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('')

答案 4 :(得分:0)

假设最大字符串长度不是一百万而是一个更低的数字,我会使用一个包含2列和2 ^ max字符串长度行的查找表,其中包含char字符串和相应的二进制值。然后,您可以将两个字符串连接到查找表的2个实例,并对结果使用按位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