SQL 仅提取字符串中关键字后的单个单词或数字

SQL to ONLY Extract Single Word or Number after a Keyword in String

SELECT 
 NOTE_ID    
,NOTE_DATE  
,NOTE_TEXT  
FROM NOTE.dbo.NOTE_TABLE

从上面的简单查询中,我得到:

NOTE_ID NOTE_DATE NOTE_TEXT
54876 2020-10-12 Purpose: Traveling Salesman Visit Customer Name: John Doe Date Account
Opened: 6/8/19 Customer Address: 428 S. Palm Tree Lane Lokey AZ 85546 Primary
Account Rep: Hank Stank Customer Account #: 1234567 Customer Preferred
Contact Time: Evenings Customer Owns/Rents: Owns Customer Employed: Yes
Customer Military Discount: No Customer Returns: No

我希望能够仅提取客户帐户#“1234567”(或者如果它为空/“未知”-客户帐户#之后和客户首选联系时间之前的任何内容。我已经尝试了各种子字符串函数来进入客户帐号#,但无法删除其后的所有内容。如有任何建议,我们将不胜感激。

请注意,NOTE_TEXT 字段全部在一行中。不确定为什么它显示为多行分解。

我确定可能有更好的方法来执行此操作,但它应该与短语 Customer Account #:

相匹配
DECLARE @searchPhrase AS CHAR(20) = 'Customer Account #: ';
SELECT IIF(PhraseExists > 0, SUBSTRING(CustomerNumNextPhrase, 0, CHARINDEX(' ', CustomerNumNextPhrase)), 'UNKNOWN') AS Account
FROM (SELECT CHARINDEX(@searchPhrase, NotesData) AS PhraseExists,
             REPLACE(NotesData, SUBSTRING(NotesData, 0, CHARINDEX(@searchPhrase, NotesData) + 20), '') AS CustomerNumNextPhrase
      FROM test.dbo.Notes) A;

如果找不到短语 Customer Account #: ,则内部查询报告 0,在这种情况下,外部查询报告 UNKNOWN。如果内部查询报告除 0 以外的任何内容,它会 returns 主字符串的子字符串,其中它会切断 Customer Account #: 之前的所有内容以及 Customer Account #: 短语本身。然后外部查询获取下一个关键字的子字符串,直到下一个 space.

对于复杂的字符串解析(SQL 确实不太擅长),我使用 CROSS APPLY 的层,这样我可以一次找到一个片段。它确实帮助我跟踪每一层并逐步调试每一层。

DROP TABLE IF EXISTS #Note
Create Table #Note (
    NOTE_ID INT PRIMARY KEY
    ,NOTE_DATE DATE
    ,NOTE_TEXT Varchar(1000)
)

INSERT INTO #Note
Values(54876,'2020-10-12', 'Purpose: Traveling Salesman Visit Customer Name: John Doe Date Account Opened: 6/8/19 Customer Address: 428 S. Palm Tree Lane Lokey AZ 85546 Primary Account Rep: Hank Stank Customer Account #: 1234567 Customer Preferred Contact Time: Evenings Customer Owns/Rents: Owns Customer Employed: Yes Customer Military Discount: No Customer Returns: No')
,(62345,'2020-11-11', 'Customer Account #: 123 blah') /*Value at beginning of text*/
,(67890,'2021-02-28', 'Blah Customer Account #: 456') /*Value at end of text*/
,(99999,'2022-01-01', 'No matching account #') 



DECLARE @SearchPhrase AS Varchar(20) = 'Customer Account #:';

SELECT *
    ,AccountNumberParsedFromNote = SUBSTRING(NOTE_TEXT,B.IDX1,C.IDX2-B.IDX1)
FROM #Note AS A
CROSS APPLY (SELECT IDX1 = NULLIF(CHARINDEX(@SearchPhrase, NOTE_TEXT),0) + LEN(@SearchPhrase) + 1) AS B /*Index of letter after search phrase*/
CROSS APPLY (SELECT IDX2 = CHARINDEX(' ',NOTE_TEXT + ' '/*Trailing space accounts for value at end of string*/,B.IDX1)) AS C /*Index of end of next word after search phrase*/