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”的正确行
如果 [收件人] 列中有邮件 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”的正确行