Sql server 获取或2个0,1字符串的最佳方法

Sql server 获取或2个0,1字符串的最佳方法,sql-server,bit,Sql Server,Bit,我有两个字符串,只包含0和1。我想要一个按位或逐字符的结果字符串 DECLARE @str1 nvarchar; DECLARE @str2 nvarchar; SET @str1= '11001100'; SET @str2= '00100110'; -- I want result to be : 11101110 字符串的大小是可变的。我可以一个接一个地使用for循环和/或字符。但是字符串的数量是可变的,它们的大小可能超过一百万。。。有比FOR loop更好的方法吗?试试下面的方法

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

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

-- I want result to be : 11101110
字符串的大小是可变的。我可以一个接一个地使用for循环和/或字符。但是字符串的数量是可变的,它们的大小可能超过一百万。。。有比FOR loop更好的方法吗?

试试下面的方法

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

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]

理想情况下,您可以将其编码为二进制

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,其中每个字符都是一个节点 -用位和序数对它们进行赋值 -按顺序加位连接

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 string length行的查找表,其中包含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

你看到这行了吗?有没有比loopOps更好的方法,我没看到。但它可以是内部定义的函数。为什么这些字符串不仅仅是二进制数据?您正在使用字节来表示位。在任何情况下,CLR都可能是迄今为止性能最好的方式。最大字符串长度为一百万,或者字符串数量为一百万,而最大长度较短?有按位或和运算符|,&。我想你可以用它们来代替你的公式n1+n2-n1*n2.&n1*n2.由于您仍在解析函数中的字符串,因此在解析时重写函数以接受两个参数Value1和Value2,或者在函数中接受它们是合乎逻辑的。因此,您可以避免完全联接。顺便说一句,使用递归CTE解析字符串比使用数字表等其他方法要慢:完全同意函数可以而且应该针对特定情况进行逻辑上的重新分解和优化,我相信问题的作者会自己做这件事。至于性能,我的意思是递归CTE是比过程循环更有效的解决方案。
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