Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 逗号分隔值(CSV)参数筛选_Sql_Sql Server_Performance_Csv - Fatal编程技术网

Sql 逗号分隔值(CSV)参数筛选

Sql 逗号分隔值(CSV)参数筛选,sql,sql-server,performance,csv,Sql,Sql Server,Performance,Csv,需要有关如何改进SQL脚本以获得更好性能的帮助dbo.Products表有一百万行。我不太愿意用动态SQL重写它。谢谢 DECLARE @Brand varchar(MAX) = 'Brand 1, Brand 2, Brand 3', @ItemCategory varchar(MAX) = 'IC1, IC2, IC3, IC4, IC5' --will return all records if params where set to @Brand = NULL, @It

需要有关如何改进SQL脚本以获得更好性能的帮助
dbo.Products
表有一百万行。我不太愿意用动态SQL重写它。谢谢

DECLARE
    @Brand varchar(MAX) = 'Brand 1, Brand 2, Brand 3',
    @ItemCategory varchar(MAX) = 'IC1, IC2, IC3, IC4, IC5'

--will return all records if params where set to @Brand = NULL, @ItemCategory = NULL

SELECT
     [Brand],
     SUM([Amount]) AS [Amount] 
FROM dbo.Products (NOLOCK)
LEFT JOIN [dbo].[Split](@Brand, ',') FilterBrand ON Brand = [FilterBrand].[Items]
LEFT JOIN [dbo].[Split](@ItemCategory, ',') FilterItemCategory ON ItemCategory = [FilterItemCategory].[Items] 
WHERE
    (@Brand IS NULL OR (@Brand IS NOT NULL AND [FilterBrand].[Items]  IS NOT NULL)) AND
    (@ItemCategory IS NULL OR (@ItemCategory IS NOT NULL AND [FilterItemCategory].[Items] IS NOT NULL))
GROUP BY
     [Brand]
下面是我在web上找到的拆分表值函数:

CREATE function [dbo].[Split]
(
    @String     varchar(8000),
    @Delimiter  char(1)
)
RETURNS @Results TABLE (Items varchar(4000))
AS
BEGIN
    IF (@String IS NULL OR @String = '') RETURN

    DECLARE @i int, @j int

    SELECT @i = 1

    WHILE @i <= LEN(@String)
        BEGIN
            SELECT  @j = CHARINDEX(@Delimiter, @String, @i)

            IF @j = 0
                BEGIN
                    SELECT  @j = len(@String) + 1
                END

            INSERT  @Results SELECT RTRIM(SUBSTRING(@String, @i, @j - @i))

            SELECT  @i = @j + LEN(@Delimiter)
        END

    RETURN
END
创建函数[dbo].[Split]
(
@字符串varchar(8000),
@分隔符字符(1)
)
返回@Results表(Items varchar(4000))
作为
开始
如果(@String为NULL或@String='')返回
声明@i int,@j int
选择@i=1

而@i这是我使用的函数。我还有另一个方法,它包装这个函数以返回数值,我觉得这也很有用

Edit:很抱歉,至于如何提高查询的性能,我通常将值拆分为表变量,并执行与表变量的联接,但这可能不会改变性能,只会改变可读性。在性能方面,我所能看到的唯一一件事就是反复检查联接是否产生任何结果。使用两个表上的两个条件左联接,您真的无法获得更好的性能。在这一点上,它基本上归结为索引

(@Brand IS NULL OR [FilterBrand].[Items] IS NOT NULL)
功能:

ALTER FUNCTION [dbo].[fn_SplitDelimittedList]
(
    @DelimittedList varchar(8000),
    @Delimitter varchar(20)
)
RETURNS 
@List TABLE 
(
    Item varchar(100)
)
AS
BEGIN
    DECLARE @DelimitterLength INT
    SET @DelimitterLength = LEN(@Delimitter)

    -- Tack on another delimitter so we get the last item properly
    set @DelimittedList = @DelimittedList + @Delimitter

    declare @Position int
    declare @Item varchar(500)

    set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
    while (@Position <> 0)
    begin
        set @Position = @Position - 1
        set @Item = LTRIM(RTRIM(left(@DelimittedList, @Position)))

        INSERT INTO @List (Item) VALUES (@Item)

        set @DelimittedList = stuff(@DelimittedList, 1, @Position + @DelimitterLength, '')
        set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
    end

    RETURN
END
ALTER函数[dbo]。[fn\u splitdiffertedlist]
(
@限定列表varchar(8000),
@瓦查尔(20)
)
返回
@列表表
(
项目varchar(100)
)
作为
开始
声明@differenterlength INT
设置@differenterlength=LEN(@differenter)
--钉上另一个定界器,以便我们正确地获得最后一项
设置@differatedList=@differatedList+@differatter
声明@positionint
声明@Item varchar(500)
设置@Position=patindex('%'+@dividexter+'%',@dividectedlist)
而(@位置0)
开始
设置@Position=@Position-1
设置@Item=LTRIM(RTRIM(左(@diffectedlist,@Position)))
插入@List(Item)值(@Item)
设置@differtedlist=stuff(@differtedlist,1,@Position+@differterlength,,)
设置@Position=patindex('%'+@dividexter+'%',@dividectedlist)
结束
返回
结束

以下是我使用的函数。我还有另一个方法,它包装这个函数以返回数值,我觉得这也很有用

Edit:很抱歉,至于如何提高查询的性能,我通常将值拆分为表变量,并执行与表变量的联接,但这可能不会改变性能,只会改变可读性。在性能方面,我所能看到的唯一一件事就是反复检查联接是否产生任何结果。使用两个表上的两个条件左联接,您真的无法获得更好的性能。在这一点上,它基本上归结为索引

(@Brand IS NULL OR [FilterBrand].[Items] IS NOT NULL)
功能:

ALTER FUNCTION [dbo].[fn_SplitDelimittedList]
(
    @DelimittedList varchar(8000),
    @Delimitter varchar(20)
)
RETURNS 
@List TABLE 
(
    Item varchar(100)
)
AS
BEGIN
    DECLARE @DelimitterLength INT
    SET @DelimitterLength = LEN(@Delimitter)

    -- Tack on another delimitter so we get the last item properly
    set @DelimittedList = @DelimittedList + @Delimitter

    declare @Position int
    declare @Item varchar(500)

    set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
    while (@Position <> 0)
    begin
        set @Position = @Position - 1
        set @Item = LTRIM(RTRIM(left(@DelimittedList, @Position)))

        INSERT INTO @List (Item) VALUES (@Item)

        set @DelimittedList = stuff(@DelimittedList, 1, @Position + @DelimitterLength, '')
        set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
    end

    RETURN
END
ALTER函数[dbo]。[fn\u splitdiffertedlist]
(
@限定列表varchar(8000),
@瓦查尔(20)
)
返回
@列表表
(
项目varchar(100)
)
作为
开始
声明@differenterlength INT
设置@differenterlength=LEN(@differenter)
--钉上另一个定界器,以便我们正确地获得最后一项
设置@differatedList=@differatedList+@differatter
声明@positionint
声明@Item varchar(500)
设置@Position=patindex('%'+@dividexter+'%',@dividectedlist)
而(@位置0)
开始
设置@Position=@Position-1
设置@Item=LTRIM(RTRIM(左(@diffectedlist,@Position)))
插入@List(Item)值(@Item)
设置@differtedlist=stuff(@differtedlist,1,@Position+@differterlength,,)
设置@Position=patindex('%'+@dividexter+'%',@dividectedlist)
结束
返回
结束

他们只需尝试我创建的拆分函数,而不使用任何while循环。只需使用此函数代替拆分函数,并在左联接中使用col匹配即可

ALTER function dbo.SplitString(@inputStr varchar(1000),@del varchar(5))
RETURNS @table TABLE(col varchar(100))
As
BEGIN

DECLARE @t table(col1 varchar(100))
INSERT INTO @t
select @inputStr

if CHARINDEX(@del,@inputStr,1) > 0
BEGIN
;WITH CTE as(select ROW_NUMBER() over (order by (select 0)) as id,* from @t)
,CTE1 as (
select id,ltrim(rtrim(LEFT(col1,CHARINDEX(@del,col1,1)-1))) as col,RIGHT(col1,LEN(col1)-CHARINDEX(@del,col1,1)) as rem from CTE
union all
select c.id,ltrim(rtrim(LEFT(rem,CHARINDEX(@del,rem,1)-1))) as col,RIGHT(rem,LEN(rem)-CHARINDEX(@del,rem,1))
from CTE1 c
where CHARINDEX(@del,rem,1)>0
)

INSERT INTO @table 
select col from CTE1
union all
select rem from CTE1 where CHARINDEX(@del,rem,1)=0
END
ELSE
BEGIN
INSERT INTO @table 
select col1 from @t
END


RETURN

END


DECLARE @Brand varchar(MAX) = 'Brand 1,Brand 2,Brand 3',
        @ItemCategory varchar(MAX) = ' IC1 A ,IC2 B , IC3 C, IC4 D' --'IC1, IC2, IC3, IC4, IC5'

select * from dbo.SplitString(@ItemCategory,',')

嘿,试试我创建的拆分函数,这里不使用任何while循环。用它代替拆分函数,用col匹配左连接

ALTER function dbo.SplitString(@inputStr varchar(1000),@del varchar(5))
RETURNS @table TABLE(col varchar(100))
As
BEGIN

DECLARE @t table(col1 varchar(100))
INSERT INTO @t
select @inputStr

if CHARINDEX(@del,@inputStr,1) > 0
BEGIN
;WITH CTE as(select ROW_NUMBER() over (order by (select 0)) as id,* from @t)
,CTE1 as (
select id,ltrim(rtrim(LEFT(col1,CHARINDEX(@del,col1,1)-1))) as col,RIGHT(col1,LEN(col1)-CHARINDEX(@del,col1,1)) as rem from CTE
union all
select c.id,ltrim(rtrim(LEFT(rem,CHARINDEX(@del,rem,1)-1))) as col,RIGHT(rem,LEN(rem)-CHARINDEX(@del,rem,1))
from CTE1 c
where CHARINDEX(@del,rem,1)>0
)

INSERT INTO @table 
select col from CTE1
union all
select rem from CTE1 where CHARINDEX(@del,rem,1)=0
END
ELSE
BEGIN
INSERT INTO @table 
select col1 from @t
END


RETURN

END


DECLARE @Brand varchar(MAX) = 'Brand 1,Brand 2,Brand 3',
        @ItemCategory varchar(MAX) = ' IC1 A ,IC2 B , IC3 C, IC4 D' --'IC1, IC2, IC3, IC4, IC5'

select * from dbo.SplitString(@ItemCategory,',')

以下解决方案没有使用函数

Declare @IDs Varchar(100)
SET @IDs = '2,4,6'

Select IsNull(STUFF((Select ', '+ CAST([Name] As Varchar(100)) From [TableName]
Where CharIndex(','+Convert(Varchar,[ID])+',', ','+@IDs+',')> 0
For XML Path('')),1,1,''),'') As [ColumnName]

以下解决方案没有使用函数

Declare @IDs Varchar(100)
SET @IDs = '2,4,6'

Select IsNull(STUFF((Select ', '+ CAST([Name] As Varchar(100)) From [TableName]
Where CharIndex(','+Convert(Varchar,[ID])+',', ','+@IDs+',')> 0
For XML Path('')),1,1,''),'') As [ColumnName]

几件事:(1)您真的需要
产品
中的所有列吗?如果没有-请不要使用
选择*
,而是显式指定列列表。这可能会为性能调整提供机会;(2) 确保
JOIN
s中涉及的所有列都已正确索引;我最近记录了一些更有效的分割字符串的方法:&@marc_我修改了我的示例脚本。我在现实生活中没有使用“选择*”。。。谢谢。@AaronBertrand哇,谢谢,我将尝试您的建议以下几点:(1)您真的需要
产品中的所有栏目吗?如果没有-请不要使用
选择*
,而是显式指定列列表。这可能会为性能调整提供机会;(2) 确保
JOIN
s中涉及的所有列都已正确索引;我最近记录了一些更有效的分割字符串的方法:&@marc_我修改了我的示例脚本。我在现实生活中没有使用“选择*”。。。谢谢。@AaronBertrand哇,谢谢,我会试试你的推荐。我试过你的分割函数,它比我用的要快。问题是如果我有这个参数值:DECLARE@itemcegory varchar(MAX)='IC1 A,IC2 B,IC3 C,IC4 D'从dbo中选择*。SplitString(@itemcegory,,'))输出:IC1 A IC3 C IC2 B,IC3 C,IC4 DHey检查最新更新的函数。在上一次返回输出时,我犯了一个小错误。因此,这将非常有效。oops仍然存在问题。尝试声明@ItemCategory varchar(MAX)=“IC1 A”;从dbo.SplitString(@ItemCategory,,')中选择*;传递给LEFT或SUBSTRING函数的长度参数无效。此外,此声明@ItemCategory varchar(MAX)='';无效的长度参数传递给左侧或子字符串函数。嘿,尝试最新的查询。抱歉,我没有考虑到急速的几个条件。我尝试了您的分割函数,它比IM使用的快。