SQL SELECT 中的行 table 如果给定条件是列数据的子字符串,带有分隔符“;”子串之间

SQL SELECT rows in a table if the given condition is a substring of the column data with a separator ';' between the substrings

如果 [收件人] 列中有邮件 abc@mail,我正在尝试从 table 邮件中获取行。

简单的解决方案是 Select * from Mails where [To] = 'abc@mail'

但问题是 [收件人] 列有 123@mail;abc@mail;aabc@mail 等数据,用分号分隔 其中 To 是发送的多封电子邮件

我知道我可以做类似 Select * from Mails where [To] like '%abc@mail%' 的事情,但如果给定的邮件是另一封邮件的子字符串,那将无法解决问题。我想到了拆分字符串的方案

我有一个这样的split_string函数,

CREATE FUNCTION [dbo].[split_string]
(
@string_value NVARCHAR(MAX),
@delimiter_character CHAR(1)
)
RETURNS @result_set TABLE(splited_data NVARCHAR(MAX)
)
BEGIN
DECLARE @start_position INT,
        @ending_position INT
SELECT @start_position = 1,
        @ending_position = CHARINDEX(@delimiter_character, @string_value)
WHILE @start_position < LEN(@string_value) + 1
        BEGIN
    IF @ending_position = 0 
       SET @ending_position = LEN(@string_value) + 1
    INSERT INTO @result_set (splited_data) 
    VALUES(SUBSTRING(@string_value, @start_position, @ending_position - @start_position))
    SET @start_position = @ending_position + 1
    SET @ending_position = CHARINDEX(@delimiter_character, @string_value, @start_position)
END
RETURN
END

这将 return 拆分列中单个数据的字符串并且函数工作正常。

我尝试执行查询

Select * 
from Mails 
where 'abc@mail' in (
   Select * 
   from dbo.split_string((SELECT [To] FROM Mails) , ';')
)

这是抛出错误:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

我需要从这里开始的帮助。我正在使用 Microsoft SQL Server 2014。一点帮助将是很大的 appreciated.Thank 你

您可以使用 CHARINDEX() 函数。

select * from Mails where CHARINDEX('abc@mail.com', To) > 0

CHARINDEX 函数检查给定字符串中的子字符串,returns 如果找到则检查一个大于零的值。此处要搜索的字符串(子字符串)为 'abc@mail.com',要搜索的主要字符串为“收件人”列。

有关 CHARINDEX() 函数的更多信息可以在下面找到 link https://www.techonthenet.com/sql_server/functions/charindex.php#:~:text=SQL%20Server%3A%20CHARINDEX%20Function%201%20Description.%20In%20SQL,use%20the%20CHARINDEX%20function%20in%20SQL%20Server%20%28Transact-SQL%29.

您不能将 multi-row 子查询作为参数传递给 dbo.split_string 函数。尝试将 table 函数加入 Mails table:

SELECT DISTINCT ms.*
    FROM Mails AS ms
    CROSS APPLY dbo.split_string(ms.[To], ';') AS s
    WHERE s.splited_data LIKE 'abc@mail'

如果您可以将 SQL 服务器升级到 2016 (13.x),您可以使用 built-in STRING_SPLIT table 函数而不是自定义 dbo.split_string.

或者,您可以通过蛮力实现您的目标,并将比较分解为简单的术语,例如:

SELECT * 
    FROM Mails 
    WHERE 
        [To] LIKE 'abc@mail'
        OR [To] LIKE '%;abc@mail;%'
        OR [To] LIKE 'abc@mail;%' 
        OR [To] LIKE '%;abc@mail'

这可能不是最好的方法,但它非常简单并且不需要拆分功能。

TL;DR; 这是您想要的查询

SELECT *
FROM dbo.Mails AS m
WHERE EXISTS (
    SELECT *
    FROM dbo.split_string(m.[To], ';') s
    WHERE s.splited_data = 'abc@mail'
)

我推荐拆分方法。任何字符查找都必须考虑 semi-colons 的可变性,而将其拆分将处理 semi-colons 所在位置的歧义,然后您可以进行直接相等性检查。如果你想更进一步,寻找额外的 [To] 地址,你可以像这样添加一个 IN 子句,SQL 服务器不需要做更多的工作,你会得到相同的结果。

SELECT *
FROM dbo.Mails AS m
WHERE EXISTS (
    SELECT *
    FROM dbo.split_string(m.[To], ';') s
    WHERE s.splited_data IN ('abc@mail', 'def@mail')
)

我的回答与@Kitta 的回答非常相似,因为我们将数据拆分出来,@Kitta 关于 IN 子句的说法是正确的,但是虽然他们的回答可行,但需要您将数据重新分组以获得单一的答案。使用 EXISTS 子句将为您绕过所有这些,只为您提供原始 table 中的数据。话虽这么说,如果他们的答案对您同样有效,请将@Kitta 标记为答案。

这是我使用的测试设置

DROP TABLE Mails
GO
CREATE TABLE Mails
([To] VARCHAR(3000))

INSERT INTO dbo.Mails
(
    [To]
)
VALUES
('123@mail;abc@mail;aabc@mail')
,('nottheone@mail.com')
,('nottheone@mail.com;Overhere@mail.com')
,('aabc@mail;ewrkljwe@mail')
,('ewrkljwe@mail')

GO
DROP FUNCTION [split_string]
GO
CREATE FUNCTION [dbo].[split_string]
(
@string_value NVARCHAR(MAX),
@delimiter_character CHAR(1)
)
RETURNS @result_set TABLE(splited_data NVARCHAR(MAX)
)
BEGIN
DECLARE @start_position INT,
        @ending_position INT
SELECT @start_position = 1,
        @ending_position = CHARINDEX(@delimiter_character, @string_value)
WHILE @start_position < LEN(@string_value) + 1
        BEGIN
    IF @ending_position = 0 
       SET @ending_position = LEN(@string_value) + 1
    INSERT INTO @result_set (splited_data) 
    VALUES(SUBSTRING(@string_value, @start_position, @ending_position - @start_position))
    SET @start_position = @ending_position + 1
    SET @ending_position = CHARINDEX(@delimiter_character, @string_value, @start_position)
END
RETURN
END
GO


SELECT *
FROM dbo.Mails AS m
WHERE EXISTS (
    SELECT *
    FROM dbo.split_string(m.[To], ';') s
    WHERE s.splited_data = 'abc@mail'
)
    

并且它 returns 是“123@mail;abc@mail;aabc@mail”的正确行