【问题标题】:TSQL: Find a continuous number in a stringTSQL:在字符串中查找连续数字
【发布时间】:2019-12-13 08:33:50
【问题描述】:

我需要在列名文件名的字符串中找到一个连续的 6 位或 7 位数字。该字符串中包含其他带有破折号的数字(或其他字符,如下划线),但我只需要连续数字

StudentID 需要从文件名中提取。 (我知道数据只是哇,多个供应商,多种文件命名格式是原因。)另一种选择是只列出连续数字的起始位置。

期望的结果:

实际结果:

测试代码:

DROP TABLE #StuID

CREATE TABLE #StuID (
 FILENAME VARCHAR(MAX)
,StudentID INT
)

INSERT INTO #StuID
( FILENAME  )
VALUES
 ('Smith John D, 11-23-1980, 1234567.pdf')
,('Doe Jane, _01_22_1980_123456.pdf')
,('John Doe, 567891.pdf' )

--This is what I tried.

SELECT FILENAME
, substring(FileName, patindex('%[0-9][0-9][0-9][0-9][0-9][0-9]%', FileName), 8) AS StudentID
FROM #StuID

【问题讨论】:

  • 是否有可能(我认为是的)有一天你会得到一个文件,文件名中的日期不是用破折号或下划线字符格式化的?如果是这样,以下解决方案将为您提供不良数据。他们会在学生 ID 之前的文件中找到 YYYYMMDD 日期或 mmddyyyy 日期......如果有人曾经向您发送一个这样命名的文件。文件的命名约定似乎有点松散。因此,如果这种情况发生,那么迄今为止的解决方案将会失败。
  • 我假设,不同的学生发送他们的作业,他们都放在一个文件夹中。每个学生都尽力以一种或另一种有意义的方式命名文件,但他们不遵守教授提供的任何命名规则;-)
  • 这实际上是一次性的,继承的问题。我的问题是文件名来自使用不同的供应商,而没有人确保标准化的文件名。从文件名中提取所需的所有数据后,希望这不再是问题。感谢大家的善意和帮助!

标签: sql sql-server tsql sql-server-2014


【解决方案1】:

因为您想要 6 位或 7 位数字,case 可能是最简单的解决方案:

SELECT FILENAME,
       (CASE WHEN FileName LIKE '%[0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
             THEN substring(FileName, patindex('%[0-9][0-9][0-9][0-9][0-9][0-9]%', FileName), 7)
             WHEN FileName LIKE '%[0-9][0-9][0-9][0-9][0-9][0-9]%'
             THEN substring(FileName, patindex('%[0-9][0-9][0-9][0-9][0-9]%', FileName), 6)
        END) AS StudentID                 
FROM #StuID

【讨论】:

  • 谢谢@GordonLinoff!我感谢帮助我开始这个的原始代码,以及帮助我​​完成这个问题的这个答案。感谢您的帮助。
【解决方案2】:

我非常喜欢的另一种方法是转换为 XML 和 XQuery 过滤器:

WITH Casted([FileName],ToXml) AS
(
    SELECT [FILENAME] 
          ,CAST('<x>' + REPLACE(REPLACE(REPLACE([FILENAME],' ','</x><x>'),'.','</x><x>'),'_','</x><x>') + '</x>' AS XML)
    FROM #StuID
)
SELECT [FileName] 
      ,numbers.value('text()[1]','int')
FROM Casted
CROSS APPLY ToXml.nodes('/x[not(empty(. cast as xs:int?))]') A(numbers);

这会将字符串拆分为其片段并返回所有片段,即数字。

您可以使用任何方便的WHERE 子句轻松地将集合缩减为 StudentID,或者向 XQuery 过滤器添加 6 或 7 的长度:

CROSS APPLY ToXml.nodes('/x[not(empty(. cast as xs:int?)) 
                            and (string-length(.)=6 or string-length(.)=7)]') A(numbers)

编辑

这将是最正确的一点

CROSS APPLY ToXml.nodes('/x[. cast as xs:int? >= 100000 and . cast as xs:int? <10000000]') A(numbers)

【讨论】:

  • 谢谢@Shnugo!这在打破一切方面做得很好。您将如何修改它以仅提取日期?
  • @JM1,由于这是一个全新的问题(并且已经有一个公认的答案),我想请你开始一个新问题并在此处放置一个链接。
  • 再次感谢您的帮助和建议,我把新问题放在这里:stackoverflow.com/questions/57374764/…
【解决方案3】:

如果您知道文件类型是 pdf,那么:

SELECT FILENAME
, substring(REPLACE(FileName, '.pdf',''), patindex('%[0-9][0-9][0-9][0-9][0-9][0-9]%', FileName), 8)
  AS StudentID
FROM #StuID;

db<>fiddle demo


更通用的一个(SQL Server 2017):

SELECT FILENAME
, substring(s.c, patindex('%[0-9][0-9][0-9][0-9][0-9][0-9]%', s.c), 8) AS StudentID
FROM #StuID
CROSS APPLY (SELECT trim(' !"#$%&\''()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' FROM filename) AS c) s

db<>fiddle demo2

【讨论】:

  • 谢谢@LukaszSzozda!我感谢您的帮助。您提供的 .pdf 答案效果很好。第二个答案在子字符串的 s.c 部分上给我一个多部分标识符错误,当我将鼠标悬停在它上面时,当我运行它时,它说关键字“FROM”附近的语法不正确。它虽然在 SQL Fiddle 中工作。它在 2016 年的服务器上,不确定这是否与它有关。感谢您发布这两个解决方案!
猜你喜欢
  • 2020-03-20
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-13
  • 2015-07-09
相关资源
最近更新 更多