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