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

How do I match a substring of variable length?

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

imptable是导入的数据,apptable是已有的数据库table.

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) 位数字?

ughai rightfully wrote in 一样,不建议在 join.
on 子句中使用除列以外的任何内容 原因是使用函数会阻止 sql 服务器在没有函数的情况下可能使用的列上使用任何索引。

因此,我建议向 imp table 添加另一列,它将保存实际的 ReceiptId 并在导入过程中计算。

我认为从 ref 列中提取 ReceiptId 的最佳方法是使用 substring with patindex, as demonstrated in this fiddle:

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

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

SELECT ref,
       CASE WHEN PATINDEX('%[ ]A[0-9][0-9][0-9][0-9][0-9| ]%', ref) > 0
       OR PATINDEX('A[0-9][0-9][0-9][0-9][0-9| ]%', ref) = 1 THEN
           SUBSTRING(ref, PATINDEX('%A[0-9][0-9][0-9][0-9][0-9| ]%', ref), 6) 
       ELSE
           NULL
       END As ReceiptId 
FROM imp

fiddle here

如果没有匹配项,这将 return 为 null, 当匹配是包含 A 后跟 4 或 5 位数字的子字符串时,与字符串的其余部分用空格分隔,并且可以在字符串的开头、中间或结尾找到。

试试这个,它会删除 A[number][number][number][number] 之前的所有字符并取其后的前 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)
  )

使用equal时,不计算后面的空格