从 id 不在 id 列表中的表中选择
Posted
技术标签:
【中文标题】从 id 不在 id 列表中的表中选择【英文标题】:Select from table where ids are not in list of ids 【发布时间】:2020-02-11 08:27:15 【问题描述】:我正在尝试从 primary_no
(VARCHAR(20)
) 不包含 @IDS 变量中的任何字符串的表中进行选择,但它不起作用,我尝试使用 CTE,不存在并且不进去。他们都不工作。查询仍然选择所有数据,即使是 @IDS 变量中具有 primary_no 的数据。
ALTER PROCEDURE [dbo].[LinkProc]
@IDS VARCHAR(MAX)
/*
DECLARE @IDS VARCHAR(MAX)
SET @IDS = '
''00000447'',
''0000300'',
''2900071'',
''2900192''
'
EXEC LinkProc @IDS = @IDS
*/
AS
WITH cte (id) AS
(
SELECT *
FROM dbo.splitstring(@IDS)
)
SELECT *
FROM link_tb
WHERE grp_id = 4
AND status_cd = 'A'
AND primary_no NOT IN (SELECT id FROM cte)
我也试过这个,但没有运气:
SELECT *
FROM link_tb lt
WHERE grp_id = 4
AND status_cd = 'A'
AND NOT EXISTS (SELECT id FROM cte c WHERE lt.primary_no = c.id)
调用(SELECT id FROM cte
)的结果集:
'00000447'
'0000300'
'2900071'
'2900192'
我找到了解决这个问题的方法,我在下面回答。
【问题讨论】:
我们手动创建了这个拆分字符串函数。所以当我调用它时 (SELECT * FROM dbo.splitstring(@IDS) 它确实给了我一个拆分字符串的列表。 【参考方案1】:免责声明:事实证明,从 chat 来看,OP 使用的不是 2014 年,而是 2005 年(完全不受支持,并且已经使用了多年)。因此,使用表类型参数的答案将不起作用,因为该功能不存在。
不过,我已将答案留在那里,以供未来有类似问题的用户使用。
不要使用分隔列表,而是使用表格类型参数
CREATE TYPE dbo.PrimaryList AS TABLE (primary_no varchar(20) NOT NULL);
GO
ALTER PROC dbo.LinkProc @IDs dbo.PrimaryList READONLY AS
BEGIN
SELECT *
FROM dbo.link_tb l
LEFT JOIN @IDs I ON l.primary_no = I.primary_no
WHERE grp_id = 4
AND status_cd = 'A'
AND I.primary_no IS NULL;
END;
GO
然后您可以这样调用 SP:
DECLARE @IDs dbo.PrimaryList;
INSERT INTO @IDs
VALUES('00000447'),
('0000300'),
('2900071'),
('2900192');
EXEC dbo.LinkProc @IDs;
编辑: 至于为什么你所拥有的东西不起作用,那是因为你引用了你的价值观。你正在做的是相当于:
EXEC dbo.LinkProc @IDs = '''00000447''';
primary_no
的值不会是 '00000447'
,它只会是 00000447
。如果您必须传递一个分隔列表(我建议不要这样做,如果您的函数使用WHILE
,我不会感到惊讶,如果您需要删除它),然后不要引用值:
EXEC dbo.LinkProc @IDs = '00000447,0000300,2900071,2900192';
【讨论】:
我传入的@IDS 来自另一个表,IDS 的列表可能很长。有没有办法在不对值进行硬编码的情况下做到这一点? 是的,使用INSERT INTO...SELECT...FROM
声明 @hypnagogia ,而不是 INSERT INTO...VALUES...
声明
如果你可以有一个很长的列表,那么使用表值参数是一个更好的主意,@hypnagogia。使用IN
的语句的性能可能会因(非常)长的列表而降低。
我在尝试实施您的解决方案时遇到了错误。我可能写错了。但是对于您提到的 INSERT INTO...SELECT...FROM,我不会从查询中的表中进行选择,而是将@IDS 列表作为参数发送。
这就是我在上面所做的,@hypnagogia:EXEC dbo.LinkProc @IDs;
【参考方案2】:
这是我的问题的解决方案。 IDS 被解析成一个表,我从那里选择。我的主要问题是我设置了格式不正确的@IDS,字符串中有换行符。把它们放在一起没有空格就可以了。
ALTER PROCEDURE [dbo].[LinkProc]
@IDS VARCHAR(MAX)
/*
DECLARE @IDS VARCHAR(MAX)
SET @IDS = '00000447,0000300,2900071,2900192'
EXEC LinkProc @IDS = @IDS
*/
AS
SELECT *
FROM link_tb
WHERE grp_id = 4
AND status_cd = 'A'
AND primary_no NOT IN (SELECT param_value FROM dbo.PARSE_PARAM_LIST(@IDS, ','))
【讨论】:
以上是关于从 id 不在 id 列表中的表中选择的主要内容,如果未能解决你的问题,请参考以下文章