如何限制子字符串以在SQL Server中的两个空格之间提取文本?

时间:2017-06-22 15:14:53

标签: sql sql-server tsql

如何限制子字符串以在SQL Server中的两个空格之间提取文本?

2017-03-09 Today ABC.XYZ Work_In_Progress 

输出应为:

ABC.XYZ

我可以从第二个空间拉出但不能限制到第三个空间:

SELECT ID, SUBSTRING(HISTORY, CHARINDEX(' ', HISTORY, CHARINDEX(' ', HISTORY) +1)+1,LEN(HISTORY)) 
from Test;

4 个答案:

答案 0 :(得分:5)

如果您知道"位置"还有另一种选择。你要去。在这种情况下,第3个字符串

mpl::push_back

<强>返回

Declare @YourTable table (ID int,SomeColumn varchar(max))
Insert Into @YourTable values
(1,'2017-03-09 Today ABC.XYZ Work_In_Progress')


Select ID
      ,SomeValue = Cast('<x>' + replace(SomeColumn,' ','</x><x>')+'</x>' as xml).value('/x[3]','varchar(max)')
 From @YourTable

XML安全版

ID  SomeValue
1   ABC.XYZ

答案 1 :(得分:3)

以下是使用CharindexSubstring的一种方法。

DECLARE @str VARCHAR(100) = '2017-03-09 Today ABC.XYZ Work_In_Progress' 

SELECT Substring(string, scd+1, thrd - scd) AS Result 
FROM   (SELECT @str                 string, 
               Charindex(' ', @str) AS fst) A 
       CROSS apply(VALUES (Charindex(' ', string, fst + 1))) cs (scd) 
       CROSS apply(VALUES (Charindex(' ', string, scd + 1))) cs1 (thrd) 

答案 2 :(得分:2)

如果您获取NGrams8K的副本,则可以创建名为SubstringBetween8K的此函数:

CREATE FUNCTION dbo.substringBetween8K
(
  @string    varchar(8000),
  @start     tinyint,
  @stop      tinyint,
  @delimiter char(1)
)
/*****************************************************************************************
Purpose:
 Takes in input string (@string) and returns the text between two instances of a delimiter
 (@delimiter); the location of the delimiters is defined by @start and @stop. 

 For example: if @string = 'xx.yy.zz.abc', @start=1, @stop=3, and @delimiter = '.' the
 function will return the text: yy.zz; this is the text between the first and third
 instance of "." in the string "xx.yy.zz.abc". 

Compatibility: 
 SQL Server 2008+

Syntax:
--===== Autonomous use
 SELECT sb.token, sb.position, sb.tokenLength
 FROM dbo.substringBetween8K(@string, @start, @stop, @delimiter); sb;

--===== Use against a table
 SELECT sb.token, sb.position, sb.tokenLength
 FROM SomeTable st
 CROSS APPLY dbo.substringBetween8K(st.SomeColumn1, 1, 2, '.') sb;

Parameters:
 @string    = varchar(8000); Input string to parse
 @delimiter = char(1); this is the delimiter use to determine where the output starts/ends
 @start     = tinyint; the first instance of @delimiter to search for; this is where the 
              output should start. When @start is 0 then the function will return 
              everything from the beginning of @string until @end. 
 @stop      = tinyint; the last instance of @delimiter to search for; this is where the 
              output should end. When @end is 0 then the function will return everything
           from @start until the end of the string. 

Return Types:
 Inline Table Valued Function returns:
 token       = varchar(8000); the substring between the two instances of @delimiter defined by 
               @start and @stop
 position    = smallint; the location of where the substring begins
 tokenlength = length of the return token

---------------------------------------------------------------------------------------
Developer Notes:
 1. Requires NGrams8K. The code for NGrams8K can be found here:
    http://www.sqlservercentral.com/articles/Tally+Table/142316/

 2. This function is what is referred to as an "inline" scalar UDF." Technically it's an 
    inline table valued function (iTVF) but performs the same task as a scalar valued user
    defined function (UDF); the difference is that it requires the APPLY table operator 
    to accept column values as a parameter. For more about "inline" scalar UDFs see this
    article by SQL MVP Jeff Moden: http://www.sqlservercentral.com/articles/T-SQL/91724/ 
    and for more about how to use APPLY see the this article by SQL MVP Paul White:
    http://www.sqlservercentral.com/articles/APPLY/69953/.

    Note the above syntax example and usage examples below to better understand how to
    use the function. Although the function is slightly more complicated to use than a
    scalar UDF it will yield notably better performance for many reasons. For example, 
    unlike a scalar UDFs or multi-line table valued functions, the inline scalar UDF does
    not restrict the query optimizer's ability generate a parallel query execution plan.

 3. dbo.substringBetween8K is deterministic; for more about deterministic and 
    nondeterministic functions see https://msdn.microsoft.com/en-us/library/ms178091.aspx

Examples:
DECLARE @string  varchar(8000) = '123.ABC456.333.222.3333XXX.$$$'

-- beginning of string to 2nd delimiter, 2nd delimiter to end of the string
SELECT '0, 2',   * FROM dbo.substringBetween8K(@string,0,2, '.')   UNION ALL
SELECT '2, 0',   * FROM dbo.substringBetween8K(@string,2,0, '.')   UNION ALL

-- Between the 1st & 2nd, then 2nd & 5th delimiters
SELECT '1, 2',   * FROM dbo.substringBetween8K(@string,1,2, '.')   UNION ALL
SELECT '2, 5',   * FROM dbo.substringBetween8K(@string,2,5, '.')   UNION ALL

-- dealing with NULLS, delimiters that don't exist and when @first = @last
SELECT '2, 10',  * FROM dbo.substringBetween8K(@string,2,10,'.')   UNION ALL
SELECT '1, NULL',* FROM dbo.substringBetween8K(@string,1,NULL,'.') UNION ALL
SELECT '1, 1',   * FROM dbo.substringBetween8K(@string,1,NULL,'.');

---------------------------------------------------------------------------------------
Revision History: 
 Rev 00 - 20160720 - Initial Creation - Alan Burstein
****************************************************************************************/

RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH 
chars AS
( 
  SELECT instance = 0, position = 0 WHERE @start = 0
  UNION ALL
  SELECT ROW_NUMBER() OVER (ORDER BY position), position 
  FROM dbo.NGrams8k(@string,1)
  WHERE token = @delimiter
  UNION ALL
  SELECT -1, DATALENGTH(@string)+1 WHERE @stop = 0
)
SELECT token =
         SUBSTRING
         (
           @string, 
           MIN(position)+1, 
           NULLIF(MAX(position),MIN(position)) - MIN(position)-1
         ),
       position = CAST(
         CASE WHEN NULLIF(MAX(position),MIN(position)) - MIN(position)-1 > 0 
         THEN MIN(position)+1 END AS smallint),
       tokenLength = CAST(NULLIF(MAX(position),MIN(position)) - MIN(position)-1 AS smallint)
FROM chars
WHERE instance IN (@start, NULLIF(@stop,0), -1);

要获得第3和第4空间之间的文本,您可以这样做:

DECLARE @txt varchar(100) = '2017-03-09 Today ABC.XYZ Work_In_Progress';

SELECT token
FROM dbo.substringBetween8K(@txt, 2, 3, ' ');

退货: ABC.XYZ

要对表使用,您可以这样做:

DECLARE @table TABLE(txt varchar(100));

INSERT @table VALUES ('2017-03-09 Today ABC.XYZ Work_In_Progress'), 
('2011-05-09 Today 123.999 Work_NotIn_Progress');

SELECT txt, token
FROM @table
CROSS APPLY dbo.substringBetween8K(txt, 2, 3, ' ');

<强>返回

txt                                                token
-------------------------------------------------- -------
2017-03-09 Today ABC.XYZ Work_In_Progress          ABC.XYZ
2011-05-09 Today 123.999 Work_NotIn_Progress       123.999

答案 3 :(得分:1)

您可以轻松使用LEFT和您已创建的逻辑。

DECLARE @HISTORY VARCHAR(50) = '2017-03-09 Today ABC.XYZ Work_In_Progress'

SELECT LEFT(SUBSTRING(@HISTORY, CHARINDEX(' ', @HISTORY, CHARINDEX(' ', @HISTORY) +1)+1,LEN(@HISTORY)) 
    , CHARINDEX(' ' , SUBSTRING(@HISTORY, CHARINDEX(' ', @HISTORY, CHARINDEX(' ', @HISTORY) +1)+1,LEN(@HISTORY))) - 1)