【问题标题】:Extracting a string in between two characters in sql提取sql中两个字符之间的字符串
【发布时间】:2019-05-10 15:00:03
【问题描述】:

我无法从字符串中提取所选字符

这是来自名为“TXT”的字段的值的 sn-p:

  • FNP,2018 年 10 月 9 日,PO-00123456 - F333330- FA_002056
  • FNP,18-09-2018,PO-00987654 - F010122- FA_002056
  • FNP,2017 年 12 月 28 日,PO-00123987 - F10101
  • FNP,13-03-2019,FRPO-35412 - F27272-ANNUL PO

我想提取 F333330、F010122、F10101 和 F27272

我已经尝试过 charindex、left/right 和 substring 但还没有破解它

SELECT TXT , 
CASE WHEN CHARINDEX('-',(SUBSTRING(txt,CHARINDEX('-',txt,2)+1,99)))=0
THEN 
LTRIM(RTRIM(SUBSTRING(txt,CHARINDEX('-',txt,2)+1,99)))
ELSE 
LTRIM(RTRIM(SUBSTRING(txt,CHARINDEX('-',txt,2) +1,CHARINDEX('-',SUBSTRING(txt,CHARINDEX('-',txt,2)+1,99))-1)))
END
FROM #test

我想要的行集只是显示:

  • F333330
  • F010122
  • F10101
  • F27272

我尝试了其他没有 case 语句的子字符串变体,但没有运气。有人可以帮忙吗?

谢谢, 纽姆斯

【问题讨论】:

  • 我认为您应该尝试在您的代码中执行此操作并将 SQL 复杂性降至最低,这样做时您将拥有很大的灵活性。尽量减少数据库访问,代码应该做大部分工作,如果可能的话,只在必要时访问数据库。我会在今天的下一个空闲时间帮助编写代码。
  • 你能explain to a rubber duck如何识别有趣的子串吗?如果你不能,那么实施起来将是一个相当大的挑战。是否是以“F”开头并贯穿所有以下数字的任何子字符串,至少有五位数字,直到非数字或字符串结尾?是否涉及“FNP”或其他内容?

标签: sql string tsql charindex


【解决方案1】:

这是一个使用 parsename()CROSS APPLY 的选项

示例

Declare @YourTable table (Txt varchar(500))
Insert Into @YourTable values
('FNP, 10/09/2018,PO-00123456 - F333330- FA_002056')
,('FNP, 18-09-2018,PO-00987654 - F010122- FA_002056')
,('FNP, 28/12/2017,PO-00123987 - F10101')
,('FNP, 13-03-2019,FRPO-35412 - F27272-ANNUL PO')

Select A.Txt
      ,NewValue = case when parsename(S,3) is null then parsename(S,1) else parsename(S,2) end
 From  @YourTable A
 Cross Apply (values ( replace(replace(parsename(replace(TXT,',','.'),1),'PO-','PO'),'-','.') )) B(S)

退货

Txt                                                  NewValue
FNP, 10/09/2018,PO-00123456 - F333330- FA_002056     F333330
FNP, 18-09-2018,PO-00987654 - F010122- FA_002056     F010122
FNP, 28/12/2017,PO-00123987 - F10101                 F10101
FNP, 13-03-2019,FRPO-35412 - F27272-ANNUL PO         F27272

【讨论】:

  • +1 用于巧妙的解决方案。如果字符串中存在句点,这将爆炸(我很难学会)
  • @AlanBurstein 谢谢。这也是我的担忧。
【解决方案2】:

试试这个?

DECLARE @test TABLE (TXT VARCHAR(500));
INSERT INTO @test SELECT 'FNP, 10/09/2018,PO-00123456 - F333330- FA_002056' UNION ALL
SELECT 'FNP, 18-09-2018,PO-00987654 - F010122- FA_002056' UNION ALL
SELECT 'FNP, 28/12/2017,PO-00123987 - F10101' UNION ALL 
SELECT 'FNP, 13-03-2019,FRPO-35412 - F27272-ANNUL PO';
SELECT SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, CASE WHEN CHARINDEX('-', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) = 0 THEN 99 ELSE CHARINDEX('-', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) - 1 END)
FROM @test;

...或者,多了一行:

DECLARE @test TABLE (TXT VARCHAR(500));
INSERT INTO @test SELECT 'FNP, 10/09/2018,PO-00123456 - F333330- FA_002056' UNION ALL
SELECT 'FNP, 18-09-2018,PO-00987654 - F010122- FA_002056' UNION ALL
SELECT 'FNP, 28/12/2017,PO-00123987 - F10101' UNION ALL 
SELECT 'FNP, 13-03-2019,FRPO-35412 - F27272-ANNUL PO' UNION ALL
SELECT 'FNP, 11/10/2017,PO-00112311 - F32121 regul po 112311';
SELECT SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 
    CASE 
        WHEN CHARINDEX('-', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) != 0 THEN CHARINDEX('-', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) - 1 
        WHEN CHARINDEX(' ', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) != 0 THEN CHARINDEX(' ', SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99)) - 1 
        ELSE 99
    END)
FROM @test;

...或重复次数较少的奖励(使用 CTE):

WITH x AS (
    SELECT SUBSTRING(TXT, PATINDEX('%- F%', TXT) + 2, 99) AS TXT FROM @test)
SELECT SUBSTRING(TXT, 0, 
    CASE 
        WHEN CHARINDEX('-', TXT) != 0 THEN CHARINDEX('-', TXT) - 1
        WHEN CHARINDEX(' ', TXT) != 0 THEN CHARINDEX(' ', TXT) - 1
        ELSE 99
    END)
FROM x;

【讨论】:

  • 嗨,理查德,这是超级接近!这适用于我的问题中所述的所有值,但我忘记包含此记录:“FNP,2017 年 11 月 10 日,PO-00112311 - F32121 regul po 112311”使用您的代码将给我 F32121 regul po 112311 而不仅仅是F32121。我怎样才能调整你的代码,只给我“F32121”以及其他期望的结果?
【解决方案3】:

我知道我在这里有点晚了,但是假设文本以 F 开头并且您知道好的值的最小/最大长度,这是一种快速有效的方法。对于本例,我假设该值的长度为 5-7 个字符,但可以轻松调整。

DECLARE @YourTable table (SomeId INT IDENTITY PRIMARY KEY, Txt varchar(500))
Insert Into @YourTable values
('FNP, 10/09/2018,PO-00123456 - F333330- FA_002056')
,('FNP, 18-09-2018,PO-00987654 - F010122- FA_002056')
,('FNP, 28/12/2017,PO-00123987 - F10101')
,('FNP, 13-03-2019,FRPO-35412 - F27272-ANNUL PO')


SELECT 
  t.SomeID, 
  ItemLength = MAX(r.N), 
  ItemIndex  = MAX(p.P),
  Item       = SUBSTRING(MAX(t.Txt),MAX(p.P),MAX(r.N)+1)
FROM @YourTable AS t
CROSS JOIN  (VALUES(4),(5),(6))                          AS r(N)
CROSS APPLY (VALUES('%F'+REPLICATE('[0-9A-Z]',r.N)+'%')) AS f(P)
CROSS APPLY (VALUES(PATINDEX(f.P,t.Txt)))                AS p(P)
WHERE p.P > 0
GROUP BY t.SomeId

返回:

SomeID      ItemLength  ItemIndex   Item
----------- ----------- ----------- ---------
1           6           31          F333330
2           6           31          F010122
3           5           31          F10101
4           5           30          F27272

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 2020-11-05
    • 1970-01-01
    • 2012-07-07
    • 2019-10-10
    相关资源
    最近更新 更多