SQL Server:提取特定字符串,然后连接两个表
我对SQL Server相当陌生 为了得到两个表之间的匹配:PRODUCT和CUSTOMERS,我得到了两个要连接的表 第一个表产品有14列,而第二个表客户有5列。快速查看数据后,似乎有一列是两个表之间的关系:产品中的NAMES1和客户中的NAMES2 然而,为了能够连接这些表,我需要首先从表CUSTOMERS中的不同列中提取一些字符串,因为当其他人将数据导入SQL时,有些东西弄糟了。在表CUSTOMERS的NAMES2列中,我需要的名称是下面示例中字符串James的最后一个子字符串,然后名称的其余部分继续进入右侧ID列,直到出现单词Alias 名称2 身份证件 2247 50%詹姆斯 麦卡锡·彼得森别名:詹姆斯,200874741,SQL Server:提取特定字符串,然后连接两个表,sql,sql-server,join,substring,extract,Sql,Sql Server,Join,Substring,Extract,我对SQL Server相当陌生 为了得到两个表之间的匹配:PRODUCT和CUSTOMERS,我得到了两个要连接的表 第一个表产品有14列,而第二个表客户有5列。快速查看数据后,似乎有一列是两个表之间的关系:产品中的NAMES1和客户中的NAMES2 然而,为了能够连接这些表,我需要首先从表CUSTOMERS中的不同列中提取一些字符串,因为当其他人将数据导入SQL时,有些东西弄糟了。在表CUSTOMERS的NAMES2列中,我需要的名称是下面示例中字符串James的最后一个子字符串,然后名称的
下面的用户查询它将忽略该数字之前的任何前导。在“addfk 01645”中,这将首先忽略,因为后面没有数字:
select * from product p inner join entities c
on p.numbers=cast(trim(substring(substring(c.id,patindex('%"[0-9]%',c.id)+1,len(c.id)),1,charindex('"',substring(c.id,patindex('%"[0-9]%',c.id)+1,len(c.id)))-1)) as float)
要将实体ID字段中的编号与产品编号字段中的编号进行匹配:
select * from product p inner join entities c
on p.numbers=trim(substring(substring(c.id,charindex('"',c.id)+1,len(c.id)),1,charindex('"',substring(c.id,charindex('"',c.id)+1,len(c.id)))-1))
请确保所有记录都满足此条件。并特别注意字符串中的“”。请试试这个,让我知道你的反馈
select * from product p inner join entities c on
p.[NAMES1] = concat(trim(left(trim(c.[ID]),
(case when charindex(' Alias',trim(c.[ID]))>0 then charindex(' Alias',trim(c.[ID])) when charindex(' Also known as',trim(c.[ID]))>0 then charindex(' Also known as',trim(c.[ID])) end)))
,' ',trim(right(trim(c.NAMES2),charindex(' ',reverse(trim(c.NAMES2))))))
在case语句中添加“Alias”的任何替代项:
(case when charindex(' Alias',trim(c.[ID]))>0 then charindex(' Alias',trim(c.[ID])) when charindex(' Also known as',trim(c.[ID]))>0 then charindex(' Also known as',trim(c.[ID]))
when charindex(' Good Alias',trim(c.[ID]))>0 then charindex(' Good Alias',trim(c.[ID]))end)
从您的单行示例来看,似乎只需将“Alias:”替换为in-id字段,就可以完成相同的操作
select * from PRODUCT p inner join CUSTOMER c on
p.NAMES1=replace(c.ID,'Alias: ','')
您可以使用的一种方法是string_split来查找每个字符串中的最后一个单词:
with p as
select p.*, s.value as p_name
from product p cross apply
(select top (1) s.value
from string_split(p.names1, ' ') s
where p.names1 like '% ' + s.value
) s
),
c as (
select c.*, s.value as c_name
from customer c cross apply
(select top (1) s.value
from string_split(c.names2, ' ') s
where c.names2 like '% ' + s.value
) s
)
select . . .
from p join
c
on p.p_name = c.c_name;
还有其他方法,但SQL Server的字符串处理能力非常差。您确实应该重新考虑您的数据模型,因为数据的呈现方式似乎有问题
例如,一个没有子查询的相对简单的方法使用名称的倒数来匹配:
select . . .
from products p join
customers c
on right(p.name1, charindex(' ', reverse(p.name1) + ' ')) =
right(c.name2, chardindex(' ', reverse(c.name1) + ' '))
我会这样做的
--==== Easily Consumable sample data (take note)
DECLARE @t TABLE (NAMES2 VARCHAR(100), ID VARCHAR(100));
INSERT @t VALUES
('9999 10% Walter', 'White Alias: Heisenburg ","2021991010",'),
('2247 50% James', 'McCarthy Petersson Alias: James ","200874741",');
--==== Solution
SELECT tName = f2.tName
FROM @t AS t
CROSS APPLY (VALUES(PATINDEX('%[a-zA-z]%', t.NAMES2),
CHARINDEX(' Alias:', t.ID))) AS f(Pos1, Pos2)
CROSS APPLY (VALUES(CONCAT(SUBSTRING(t.Names2, f.Pos1, 100),' ',
SUBSTRING(t.ID, 1, f.Pos2)))) AS f2(tName)
--JOIN dbo.thatOtherTable AS ot
-- ON ot.tName = f2.tName
请注意,连接已注释掉,但应该会有所帮助。这将返回:
tName
----------------------------
Walter White
James McCarthy Petersson
那是一个非常糟糕的桌子设计。你能修复它吗?还是你必须使用你所拥有的?一个例子不足以分析你的数据并决定一种方法来隔离相关信息的识别片段。在这个特定的例子中,您似乎想加入James的行列,那么这些特定值所表示的模式是否一致?现在我来看一下,这是否是由于导入失败,并且有人没有正确划分字段,并意外地将名称分割到两个单独的列之间?因此,为什么要在产品表中找到一个人的名字?这里好像出了什么事,可能是。是的,这里有些事情搞砸了,我需要处理一下。我想这应该是可能的?非常抱歉。打字错误我写的不是“on”,而是“where”。我已更改了答案。ID中存在不带子字符串“Alias”的值。所以charindex'Alias',trimc.[ID]-1返回-1,这对于left来说是无效的参数。为了解决这个问题,我改变了答案。请让我知道两个表中有多少行数据?需要解决每个异常。很费时,但如果没有其他选择,我们可以到达。您考虑过替换选项吗?如果它满足条件,速度会更快。您可以提供表中的这三列,如果您同意,我可以尝试一下。但它肯定不会正确匹配所有行。