Sql 将数据存储在两个CSV字符串和两个db表中,以实现最快的比较
情况是,我们有两个列表: A:23,45,g5,33 B:11,12,45,g9 我们希望SQL SERVER中最快的机制可以查看B中的任何值是否在A中可用,在本例中,45在A中,因此它必须返回true 解决方案应描述存储列表(CSV、表格等)的方式和比较机制Sql 将数据存储在两个CSV字符串和两个db表中,以实现最快的比较,sql,sql-server,csv,Sql,Sql Server,Csv,情况是,我们有两个列表: A:23,45,g5,33 B:11,12,45,g9 我们希望SQL SERVER中最快的机制可以查看B中的任何值是否在A中可用,在本例中,45在A中,因此它必须返回true 解决方案应描述存储列表(CSV、表格等)的方式和比较机制 每个列表都相对较小(平均每个列表中有10个值),但进行了多次比较(很少写入,多次读取)我仍然对核心思想感到困惑。。。但这里有一个比逗号分隔列表更好的简单解决方案。当然,创建索引会使它更快。这比循环快得多 declare @table ta
每个列表都相对较小(平均每个列表中有10个值),但进行了多次比较(很少写入,多次读取)我仍然对核心思想感到困惑。。。但这里有一个比逗号分隔列表更好的简单解决方案。当然,创建索引会使它更快。这比循环快得多
declare @table table (id char(4), v varchar(256))
insert into @table
values
('A','23'),
('A','45'),
('A','g5'),
('A','33'),
('B','11'),
('B','12'),
('B','45'),
('B','g9')
select distinct
base.v
--,base.*
--,compare.*
from
@table base
inner join
@table compare
on compare.v = base.v
and compare.id <> base.id
如果您被分隔的字符串所困扰,请考虑以下内容: 示例:
Declare @YourTable Table ([ColA] varchar(50),[ColB] varchar(50))
Insert Into @YourTable Values
('23,45,g5,33' ,'11,12,45,g9')
,('no,match' ,'found,here')
Select *
from @YourTable A
Cross Apply (
Select Match=IsNull(sum(1),0)
From [dbo].[udf-Str-Parse-8K](ColA,',') B1
Join [dbo].[udf-Str-Parse-8K](ColB,',') B2 on B1.RetVal=B2.RetVal
) B
返回
ColA ColB Match
23,45,g5,33 11,12,45,g9 1
no,match found,here 0
UDF如果感兴趣
CREATE FUNCTION [dbo].[udf-Str-Parse-8K] (@String varchar(max),@Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
根据前面的答案,我认为应该是这样的:
declare @table table (id char(4), v varchar(256))
insert into @table
values
('A','23'),
('A','45'),
('A','g5'),
('A','33'),
('B','11'),
('B','12'),
('B','45'),
('B','g9')
if exists( select count(1)
from
@table base
inner join
@table compare
on compare.v = base.v
and base.id='A' and compare.id='B')
print 'true'
else
print 'false'
根据数据量的增长,在id、v或v、id上建立索引?索引表应该是最快的两个列表?你是说两列?如何将它们存储在同一列中,并为您要拆分的内容指定一个ID。您尚未声明此数据是否已在SQL Server中。但是,一般来说,不要在SQLServer中将值存储为逗号分隔的字符串。无论如何,您都必须将其拆分以进行比较。如果您要求将其存储在不同的表中,而不是同一个表和不同的列中,那么这个问题很奇怪。相同的表会更快,但这不是设计数据库时要问的问题通常是关系和规范化XY问题是关于您尝试的解决方案而不是实际问题。描述你的真实情况,而不是简单明了的解决方法。停止像这样存储分隔数据。它违反1NF,使查询变得更加困难和缓慢。不错,但它比@scsimon answer快吗?@mohas很难说。仍然不是100%清楚。你在寻找任何字符串中的匹配项吗?如果是的话,我有一个alternative@mohas如果没有别的,提供的解析函数是最快的方法之一,请分享
CREATE FUNCTION [dbo].[udf-Str-Parse-8K] (@String varchar(max),@Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
declare @table table (id char(4), v varchar(256))
insert into @table
values
('A','23'),
('A','45'),
('A','g5'),
('A','33'),
('B','11'),
('B','12'),
('B','45'),
('B','g9')
if exists( select count(1)
from
@table base
inner join
@table compare
on compare.v = base.v
and base.id='A' and compare.id='B')
print 'true'
else
print 'false'