我有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
循环更好的方法?
答案 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));
}
}
答案 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