OR 2 串 0,1 的最佳方法

Best way to OR 2 strings of 0,1

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

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

-- I want result to be : 11101110

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

试试下面的方法

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

不使用循环的变体 - 纯基于集合的方法(使用递归 CTE),因此与任何类型的循环相比应该非常有效。 您可以使用这个函数来 JOIN 或 APPLY 它到其他数据集(表或视图)

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

理想情况下,您会将其编码为二进制。

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));        
    }
}

非常酷的问题和解决方案。我使用 xml 添加另一个: -将两个字符串转换为 xml 其中每个字符都是一个节点 - 使它们 table 用位和序数赋值 - 按顺序添加位

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

假设最大字符串长度不是一百万而是一个小得多的数字,我会使用一个包含 2 列和 2^max 字符串长度行的查找 table 以及 char 字符串和相应的二进制值。然后,您可以将两个字符串连接到查找的 2 个实例 table,并对结果使用按位或函数。

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