我有一张表(1号),有10列。其中一个clm01
是整数,不允许使用空值。
有第二个表(第2个),它有很多列。其中一个是字符串类型clm02
。此列数据的示例是1,2,3
。
我想提出类似的查询:
select *
from table1 t1, table2 t2
where t1.clm01 not in (t2.clm2)
例如,在表1中,我有5条记录,其值为clm01
1,2,3,4,5
,而在表格2中,我有{1}}中有1条值的记录
所以我希望查询只返回clm02 = 1,2,3
中值为4
和5
的记录。
相反,我得到:
转换varchar值时转换失败' 1,2,3'到数据类型int
有什么想法吗?
答案 0 :(得分:1)
如果您使用的是SQL Server 2016,请使用STRING_SPLIT()函数拆分逗号分隔值。
SELECT *
FROM table1 t1
WHERE t1.clm1 NOT IN (SELECT Value FROM table2 t2
CROSS APPLY STRING_SPLIT(t2.clm2,','))
如果您使用任何较低版本的SQL Server,请编写UDF以拆分字符串并使用CROSS APPLY子句中的函数。
CREATE FUNCTION [dbo].[SplitString]
(
@string NVARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @output TABLE(Value NVARCHAR(MAX)
)
BEGIN
DECLARE @start INT, @end INT
SELECT @start = 1, @end = CHARINDEX(@delimiter, @string)
WHILE @start < LEN(@string) + 1 BEGIN
IF @end = 0
SET @end = LEN(@string) + 1
INSERT INTO @output (Value)
VALUES(SUBSTRING(@string, @start, @end - @start))
SET @start = @end + 1
SET @end = CHARINDEX(@delimiter, @string, @start)
END
RETURN
END
答案 1 :(得分:0)
我决定给你一些选择,但这确实是我经常看到的重复问题。
有两种主要方法可以解决这个问题。
1)使用LIKE来比较字符串,但实际上你必须有点奇怪地构建字符串:
SELECT *
FROM
@Table1 t1
WHERE
NOT EXISTS (SELECT *
FROM @Table2 t2
WHERE ',' + t2.clm02 + ',' LIKE '%,' + CAST(t1.clm01 AS VARCHAR(15)) + ',%')
你看到的是1,2,3,就像%,clm01value,%你必须在字符串中添加分隔符才能使其正常工作,你必须将clm01转换/转换为char数据类型。这个解决方案有一些缺点,但如果您的数据集很直接,那么它可能适合您。
2)将逗号分隔的字符串拆分为行,然后使用左连接,不存在或不存在。这是将csv转换为xml然后拆分的方法
;WITH cteClm02Split AS (
SELECT
clm02
FROM
(SELECT
CAST('<X>' + REPLACE(clm02,',','</X><X>') + '</X>' AS XML) as xclm02
FROM
@Table2) t
CROSS APPLY (SELECT t.n.value('.','INT') clm02
FROM
t.xclm02.nodes('X') as t(n)) ca
)
SELECT t1.*
FROM
@Table1 t1
LEFT JOIN cteClm02Split t2
ON t1.clm01 = t2.clm02
WHERE
t2.clm02 IS NULL
或者使用NOT EXISTS与相同的cte
SELECT t1.*
FROM
@Table1 t1
WHERE
NOT EXISTS (SELECT * FROM cteClm02Split t2 WHERE t1.clm01 = t2.clm02)
有许多其他方法可以分割分隔的字符串,您可以选择适合您的任何方式。
注意:我没有显示IN / NOT IN作为答案,因为我不建议使用它。如果您确实使用它,请确保您永远不会在选择等中比较NULL。这是关于性能等的另一篇好帖子。NOT IN vs NOT EXISTS
这里是使用的表变量:
DECLARE @Table1 AS TABLE (clm01 INT)
DECLARE @Table2 AS TABLE (clm02 VARCHAR(15))
INSERT INTO @Table1 VALUES (1),(2),(3),(4),(5)
INSERT INTO @Table2 VALUES ('1,2,3')