使用SQL charindex在引号或引号之间获取引号或多个字符串之间的字符串

时间:2017-11-03 17:21:10

标签: sql sql-server database

我们必须识别来自错误导入的一些数据,并且将不胜感激任何帮助。 例如,下面的字符串和charindex的标识符char。

SET @InputString  = 'The quick brown fox jumped "over" or "under" the log'
SET @IdentifierChar = '"' 

我们遇到的问题是,我们可以针对上面的硬编码字符串运行测试,并得到“结果”的结果。我们已尝试将其置于while循环中,然后我们会在'以及'或'或'''我们的预期结果只会返回'在''而不是或。

我们第一次参加测试就像下面的内容,只是看看尝试和分裂:

DECLARE @InputString Nvarchar(MAX)
DECLARE @IdentifierChar NCHAR(1)
SET @InputString  = 'The quick brown fox jumped "over" or "under" the log'
SET @IdentifierChar = '"'

declare @FirstID int
declare @SecondID int
declare @Length int
declare @TargetString Nvarchar(MAX)

Set @FirstID = CHARINDEX(@IdentifierChar,@InputString,1)
Set @SecondID = CHARINDEX(@IdentifierChar,@InputString,@FirstID+1)
Set @Length = @SecondID-@FirstID
Set @TargetString = SUBSTRING(@InputString,@FirstID+1,@Length-1)

就像我说的那样,我们只是把它扔进一个硬编码循环中,并将子字符串的值设置为特殊字符标识符的最后位置,以便测试并查看charindex如何在引号之间拆分字符串我们没有想到它会得到“或”#39;同样。

所以这里是脏循环:

Set @COUNT = 0
Set @Length = 0
WHILE(@COUNT)<3
BEGIN
Set @FirstID = CHARINDEX(@IdentifierChar,@InputString,@Length)
Set @SecondID = CHARINDEX(@IdentifierChar,@InputString,@FirstID+1)
Set @Length = @SecondID-@FirstID
Set @TargetString = SUBSTRING(@InputString,@FirstID+1,@Length-1)
SET @COUNT = @COUNT+1
Set @Length =@SecondID
END

4 个答案:

答案 0 :(得分:0)

可能有更好的方法来解析这个问题,但这是我对代码的最小修改,以使其正常工作,并通过评论我改变了一些内容:

DECLARE @InputString Nvarchar(MAX)
DECLARE @IdentifierChar NCHAR(1)
SET @InputString  = 'The quick brown fox jumped "over" or "under" the log'
SET @IdentifierChar = '"'

declare @FirstID int
declare @SecondID int
declare @Length int
declare @TargetString Nvarchar(MAX)

declare @COUNT int   -- added this missing from your code above
Set @COUNT = 0
Set @Length = 0
WHILE(@COUNT)<2  -- only need 2 here now
BEGIN
Set @FirstID = CHARINDEX(@IdentifierChar,@InputString,@Length)
Set @SecondID = CHARINDEX(@IdentifierChar,@InputString,@FirstID+1)
Set @Length = @SecondID-@FirstID
Set @TargetString = SUBSTRING(@InputString,@FirstID+1,@Length-1)
SET @COUNT = @COUNT+1
Set @Length =@SecondID+1    -- added one
print @TargetString         -- so we can see what it finds
END

你的主要问题是在你的循环底部更新@Length - 当你认为你在&#34;&#34;之后指向PAST双引号时,你实际上正指向它并找到它时间作为开放报价之前&#34;或&#34;。

答案 1 :(得分:0)

根据数据集的大小和整体查询的复杂程度,您可以使用递归CTE:

$filepathname = 'valid file path and name'
$dest = '\DoesntExist\'

try
{
    Copy-Item $filepathname $dest  -errorAction stop
    Write-Host "Success"
}
catch
{
    Write-Host "Failure"
}

答案 2 :(得分:0)

这是我编写并保存在工具箱中的用户定义函数。这是一个略带标签的用法,但它应该适合你。

如果我们认为这个字符串是五个子字符串,由四个双引号字符分隔,那么我们可以拆分那些只需要获取子字符串2和4.(获得第三或第四个引用值就像获取子字符串一样简单6或8)尝试获取不存在的元素只会返回NULL。

执行下面的CREATE语句后会创建dbo.SPLIT_LIST函数,你可以这样调用它:

declare @InputString varchar(255)
SET @InputString  = 'The quick brown fox jumped "over" or "under" the log'

select dbo.SPLIT_LIST(@InputString, '"', 2, ''),
       dbo.SPLIT_LIST(@InputString, '"', 4, '')

你将获得两个输出值。这样的函数有什么好处,你可以把它放在你的select语句中,一次操作多条记录,而不是每条记录。

CREATE function dbo.SPLIT_LIST(
  @string nvarchar(max), 
  @delimiter nvarchar(50), 
  @i int, 
  @text_qualifier nvarchar(1)
  )

returns nvarchar(max)
/*
  returns a selected element from a delimited list

  select dbo.SPLIT_LIST_w_Qualifier('"twenty,one","twenty,two","twenty,three"', ',', 2,'"')
  returns:  'twenty,two'

  Note: can ignore embedded text qualifiers
*/

as
BEGIN


declare @value nvarchar(max),
        @d_length int,
        @next_delimiter nvarchar(51),
        @q_length int, --length of the text qualifier
        @trim int,
        @using_qualifier int

set @d_length = len(@delimiter)
set @q_length = len(@text_qualifier)
set @string = ltrim(rtrim(@string))

--works by chopping off the leading value from the string each round

while @i > 0 and @string is not null and len(@string) > 0
begin

  --if the remaining @string starts with the text qualifier, 
  --then the currently parsed value should end with the text qualifier+delimiter
  if left(@string,1) = @text_qualifier 
     begin
      set @using_qualifier = 1
      --chop off leading qualifier
      set @string = ltrim(right(@string,(len(@string)-len(@text_qualifier))))
     end
    else 
     begin
      set @using_qualifier = 0
     end

  if (@using_qualifier = 0) -- If we are NOT using a text qualifier for this element
  begin
    if (charindex(@delimiter, @string) > 0) --If there is a remaining delimiter
    begin
      set @value = ltrim(rtrim(left(@string, charindex(@delimiter, @string)-1)))
      set @string = ltrim(rtrim(right(@string, len(@string)-charindex(@delimiter, @string) - @d_length + 1)))
    end
    else --no remaining delimiters
    begin
      set @value = @string
      set @string = null
    end
  end
  else -- If we ARE using a text qualifier for this element
  begin
    if (charindex((@text_qualifier+@delimiter), @string) > 0) --If there is a remaining qualifier+delimiter
    begin
      set @value = ltrim(rtrim(left(@string, charindex((@text_qualifier+@delimiter), @string)-1)))
      set @string = ltrim(rtrim(right(@string, len(@string)-charindex((@text_qualifier+@delimiter), @string) - @d_length - @q_length + 1)))
    end
    else --no remaining qualifier+delimiters
    begin
      --Does the remaining string END with the text qualifier?
      if (charindex(REVERSE(@text_qualifier), REVERSE(@string)) = 1)
      begin
        set @value = ltrim(rtrim(left(@string, len(@string)-@q_length)))
        set @string = null
      end
      else if (charindex((@text_qualifier), @string) > 0) --Is there a remaining qualifier at all?
      begin
        set @value = ltrim(rtrim(left(@string, charindex((@text_qualifier), @string)-1)))
        set @string = null
      end
      else  --no final closing qualifier
      begin
        set @value = @string
        set @string = null
      end
    end
  end

  set @i = @i - 1

  --print @value

end

if @i = 0 return @value  --should exit here

return NULL              --a parse too far exists here

END

答案 3 :(得分:0)

只想更新。我继续玩弄代码并得到一些工作,以防将来有人想要使用类似的逻辑。这就是我们上面讨论过的。

DECLARE @TargetString NVARCHAR(MAX)
DECLARE @stringLen int
DECLARE @splitTbl TABLE(siteId NVARCHAR(MAX))
DECLARE @idChar NCHAR(1)

SET @TargetString = 'The quick brown fox jumped "over" or "under" the "log"'
SET @stringLen = CHARINDEX(' ', @TargetString)
SET @idChar = '"'

WHILE CHARINDEX(' ', @TargetString) > 0
BEGIN
SET @stringLen = CHARINDEX(' ', @TargetString);

INSERT INTO @splitTbl
SELECT SUBSTRING(@TargetString,1,@stringLen - 1);

SET @TargetString = SUBSTRING(@TargetString, @stringLen + 1, 
LEN(@TargetString));
END

DECLARE @buildResults NVARCHAR(MAX)
INSERT INTO @splitTbl
SELECT @TargetString

DECLARE @buildLike NVARCHAR(MAX)
SET @buildLike = '%'+@idChar+'%'
SELECT  @buildResults = COALESCE(@buildResults + ', ', '') 
+SUBSTRING(siteId, 2, lEN(siteId) - 2)
FROM @splitTbl
WHERE siteId LIKE @buildLike