如何匹配可变长度的子字符串?

时间:2015-05-19 07:37:09

标签: sql-server regex sql-server-2005

我正在从Excel电子表格中将数据导入我的SQL数据库。

imp表是导入的数据,app表是现有的数据库表。

app.ReceiptId的格式为" A"接着是一些数字。以前它是4位数,但现在可能是4位或5位数。

示例:

A1234
A9876
A10001

imp.ref是Excel中的自由文本引用字段。它由一些任意长度的描述组成,然后是ReceiptId,后跟一个格式为"的无关参考号。 - BZ-0987654321" (有时裁短,甚至完全丢失)。

示例:

SHORT DESC A1234 - BZ-0987654321
LONGER DESCRIPTION A9876 - BZ-123
REALLY LONG DESCRIPTION A2345 - B
REALLY REALLY LONG DESCRIPTION A23456

以下代码适用于4位ReceiptId,但无法正确捕获5位数字。

UPDATE app
SET
[...]
FROM imp
INNER JOIN app
ON app.ReceiptId = right(right(rtrim(replace(replace(imp.ref,'-',''),'B','')),5) 
                   + rtrim(left(imp.ref,charindex(' - BZ-',imp.ref))),5)

如何更改代码以便捕获4(A1234)或5(A12345)数字?

2 个答案:

答案 0 :(得分:1)

正如ughaihis comment中正确写的那样,不建议在on的{​​{1}}子句中使用除列之外的任何内容。
原因是使用函数会阻止sql server在没有函数的情况下使用它可能使用的列上的任何索引。

因此,我建议在imp表中添加另一个列,该列将保存实际的join并在导入过程中自行计算。

我认为从ReceiptId列中提取ReceiptId的最佳方法是将substringpatindex一起使用,如this fiddle中所示:

ref

<强>更新
在评论中与t-clausen-dk对话后,我想出了这个:

SELECT ref,
       RTRIM(SUBSTRING(ref, PATINDEX('%A[0-9][0-9][0-9][0-9]%', ref), 6)) As ReceiptId 
FROM imp

fiddle here

如果没有匹配,则返回null, 当匹配是包含A后跟4或5位数的子字符串时,用字符串的其余部分用空格分隔,并且可以在字符串的开头,中间或末尾找到。

答案 1 :(得分:1)

试试这个,它将删除A [编号] [编号] [编号] [编号]之前的所有字符,然后取出前6个字符:

UPDATE app
SET
[...]
FROM imp
INNER JOIN app
ON app.ReceiptId in 
  (
   left(stuff(ref,1, patindex('%A[0-9][0-9][0-9][0-9][ ]%', imp.ref + ' ') - 1, ''), 5),
   left(stuff(ref,1, patindex('%A[0-9][0-9][0-9][0-9][0-9][ ]%', imp.ref + ' ') - 1, ''), 6)
  )

当使用相等时,不评估后面的空格