Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何匹配可变长度的子字符串?_Sql Server_Regex_Sql Server 2005 - Fatal编程技术网

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

Sql server 如何匹配可变长度的子字符串?,sql-server,regex,sql-server-2005,Sql Server,Regex,Sql Server 2005,我正在将数据从Excel电子表格导入SQL数据库 imp表是导入的数据,app表是现有的数据库表 app.ReceiptId的格式为A,后跟一些数字。以前是4位数,但现在可能是4或5位数 示例: A1234 A9876 A10001 SHORT DESC A1234 - BZ-0987654321 LONGER DESCRIPTION A9876 - BZ-123 REALLY LONG DESCRIPTION A2345 - B REALLY REALLY LONG DESCRIPTION

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

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

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

示例:

A1234
A9876
A10001
SHORT DESC A1234 - BZ-0987654321
LONGER DESCRIPTION A9876 - BZ-123
REALLY LONG DESCRIPTION A2345 - B
REALLY REALLY LONG DESCRIPTION A23456
imp.ref是Excel中的自由文本引用字段。它包括一些任意长度的描述,然后是ReceiptId,然后是格式为-BZ-0987654321的不相关参考号,有时会缩短,甚至完全缺失

示例:

A1234
A9876
A10001
SHORT DESC A1234 - BZ-0987654321
LONGER DESCRIPTION A9876 - BZ-123
REALLY LONG DESCRIPTION A2345 - B
REALLY REALLY LONG DESCRIPTION A23456
下面的代码适用于4位数的ReceiptId,但不能正确捕获5位数的ReceiptId

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

如中所述,不建议在join的on子句中使用任何其他then列。 原因是使用函数会阻止sql server在不使用函数的情况下对列使用任何索引

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

我认为从ref列提取ReceiptId的最佳方法是使用with,如中所示:

更新 在评论中与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
如果没有匹配项,则返回null,
如果匹配项是一个子字符串,该子字符串包含一个后跟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时,后面的空格不计算

能否提供一些示例数据?我想一些app.receiptid和imp.Ref就足够了。此外,如果A1234被视为等同于A12345?@ZoharPeled No,则每个接收方ID都是唯一的。我将添加一些示例数据,但我认为它描述得相当好。我建议在执行join时不要特别在sql中执行此操作。sql作为一种语言不适合ETL作业,更不用说字符串解析了。SQL Server为此提供SSI。您可以导入Excel数据,使用C脚本(可能带有正则表达式)解析列,并将数据输出到目标表。如果varchar为“A1234A”,则仍将认为它有效。如果您的varchar不包含有效数据,它将从第一个字符开始进行比较,您的RTRIM也是不必要的,如果varchar不包含有效数据,那么比较无论如何都会失败,但是感谢RTRIM的建议和最后一个空格,我将编辑我的答案以修复此问题。如果varcharREF以6个空格开始,并且它无效,然后,一旦您进行比较,并且ReceiptId中有许多空的varchar,您将更新它们allExample以说明将返回一行:SELECT RTRIMSUBSTRINGref,PATINDEX“%a[0-9][0-9][0-9][0-9]”,ref,6 FROM SELECT''ref x WHERE ref=@t-clausen.dk查看我编辑的答案。感谢您查找缺陷,它帮助我改进sql。