如何匹配可变长度的子字符串?
How do I match a substring of variable length?
我正在将数据从 Excel 电子表格导入我的 SQL 数据库。
imp
table是导入的数据,app
table是已有的数据库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
如果没有匹配项,这将 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时,不计算后面的空格
我正在将数据从 Excel 电子表格导入我的 SQL 数据库。
imp
table是导入的数据,app
table是已有的数据库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
如果没有匹配项,这将 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时,不计算后面的空格