Sql server 从带分隔符的字符串中提取数字,格式不同

Sql server 从带分隔符的字符串中提取数字,格式不同,sql-server,join,Sql Server,Join,我正在尝试从运行SQL Server 2014的ERP系统中连接两个表,OrderLines和Production。其工作方式是,如果将产品添加到订单中,并且该产品没有库存,则会自动生成用于生产的“生产分录”(基本上是物料清单) OrderLines表中的GeneratedEntries字段捕获该数据,记录为该订单行生成的生产条目号。该字段通常采用以下格式:它以PD~开头,然后是条目号,随后的条目号由另一个波浪号~分隔。因此,对于导致生成2个条目号的订单行,此字段的标准值可能如下所示: PD~1

我正在尝试从运行SQL Server 2014的ERP系统中连接两个表,
OrderLines
Production
。其工作方式是,如果将产品添加到订单中,并且该产品没有库存,则会自动生成用于生产的“生产分录”(基本上是物料清单)

OrderLines
表中的
GeneratedEntries
字段捕获该数据,记录为该订单行生成的生产条目号。该字段通常采用以下格式:它以
PD~
开头,然后是条目号,随后的条目号由另一个波浪号
~
分隔。因此,对于导致生成2个条目号的订单行,此字段的标准值可能如下所示:
PD~12345~67891

问题是,该字段的格式有时不一致,有时会有尾随的波浪号,有时字符串中间会重复
PD~
,还有其他多余的垃圾字符,等等

我不知道如何从
GeneratedEntries
中提取条目号来连接两个表,这种方式适用于所有格式设置。有没有办法做到这一点

下面有相关列的示例表(OrderNumber和Product实际上并不相关,只是用于上下文…)


实际上,任何解析/拆分函数都可以。这里是一个内联方法

唯一的技巧是用~替换任何空格,用try_convert()替换过滤器

示例

Declare @YourTable Table ([OrderNumber] varchar(50),[Product] varchar(50),[GeneratedEntries] varchar(50))
Insert Into @YourTable Values 
 (1,'A','PD~10005')
,(1,'B','PD~10006~')
,(1,'C','PD~10007~10008~10009')
,(2,'R','PD~10010~~10011')
,(2,'L','~PD~10012~~')
,(2,'Z','PD~10013 PD~10014')

Select A.OrderNumber
      ,A.Product
      ,B.* 
 From @YourTable  A
 Cross Apply (
                Select RetSeq = Row_Number() over (Order By (Select null))
                      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                From  (Select x = Cast('<x>' + replace(replace([GeneratedEntries],' ','~'),'~','</x><x>')+'</x>' as xml).query('.')) as A 
                Cross Apply x.nodes('x') AS B(i)
             ) B
 Where try_convert(int,B.RetVal) is not null

OrderLines表上的主键是什么?@MaxSzczurek主键是
OrderNumber
,它通常连接到一个单独的
Orders
表,该表包含所有主订单标题信息。我认为这与这个问题无关。OrderNumber是orders表的主键,而不是OrderLines表。您需要建立每行的唯一性。OrderLines表的主键是什么?我猜它是OrderNumber和其他字段的组合,比如一行#。这与你的问题绝对相关。是的,你是对的,我的错。OrderLines的主键是OrderNumber和LineItem(如您所猜测的,第#行),非常感谢,这看起来非常有效。我不知道这一切意味着什么,但我会尝试将您的查询分开。此外,正如@MaxSzczurek正确指出的那样,我在问题中忽略了提到,
OrderLines
的主键是
OrderNumber
LineItem
。因此,我只需将
LineItem
添加到您的查询中,并在这两个字段上进行联接。@wysiwyg很高兴这有帮助,我们将完成联接。
Declare @YourTable Table ([OrderNumber] varchar(50),[Product] varchar(50),[GeneratedEntries] varchar(50))
Insert Into @YourTable Values 
 (1,'A','PD~10005')
,(1,'B','PD~10006~')
,(1,'C','PD~10007~10008~10009')
,(2,'R','PD~10010~~10011')
,(2,'L','~PD~10012~~')
,(2,'Z','PD~10013 PD~10014')

Select A.OrderNumber
      ,A.Product
      ,B.* 
 From @YourTable  A
 Cross Apply (
                Select RetSeq = Row_Number() over (Order By (Select null))
                      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                From  (Select x = Cast('<x>' + replace(replace([GeneratedEntries],' ','~'),'~','</x><x>')+'</x>' as xml).query('.')) as A 
                Cross Apply x.nodes('x') AS B(i)
             ) B
 Where try_convert(int,B.RetVal) is not null
OrderNumber Product RetSeq  RetVal
1           A       2       10005
1           B       2       10006
1           C       2       10007
1           C       3       10008
1           C       4       10009
2           R       2       10010
2           R       4       10011
2           L       3       10012
2           Z       2       10013
2           Z       4       10014