Sql server 从Microsoft SQL VarChar列中获取不存在的所有数字

Sql server 从Microsoft SQL VarChar列中获取不存在的所有数字,sql-server,Sql Server,我有一个表,其中包含一列ID号,这些ID号不会在单个步骤中增加 所以有些数字是不用的,这是我需要的。该列是一个VarChar列 例如: 表中使用的数字=2、5、7、9、10等 所以我需要一个查询,它给我=1,3,4,6,8等等 伪代码类似于: 从表中选择数字不在“从表中选择数字”中 我尝试过不存在,也不存在,但没有任何效果 有人能帮我做到这一点吗 编辑:数字范围从0到9999999 不使用CTE,您可以使用master.dbo.spt_值技巧。不确定此表在msdb中的实际用途,但它包含我们需要的

我有一个表,其中包含一列ID号,这些ID号不会在单个步骤中增加

所以有些数字是不用的,这是我需要的。该列是一个VarChar列

例如:

表中使用的数字=2、5、7、9、10等

所以我需要一个查询,它给我=1,3,4,6,8等等

伪代码类似于:

从表中选择数字不在“从表中选择数字”中

我尝试过不存在,也不存在,但没有任何效果

有人能帮我做到这一点吗


编辑:数字范围从0到9999999

不使用CTE,您可以使用master.dbo.spt_值技巧。不确定此表在msdb中的实际用途,但它包含我们需要的值。试试看。如果您的值大于spt_值,则将max id除以spt_值的max,并将数字+1替换为数字+1+@currentbatch*@maxsptvalues第一批为批次0。我还没有测试过它,也没有为它编写过代码,但这样的东西肯定会有用。例如,您可以在while循环中完成

DECLARE @Table AS TABLE
(
    Id VARCHAR(5)
)

INSERT INTO @Table
VALUES
 ('1')
,('3')
,('5')
,('7')
,('10')

DECLARE @Range AS TABLE
(
    RangeId VARCHAR(10)
)

INSERT INTO @Range
SELECT TOP (1000000) n = CONVERT(VARCHAR(10), ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1)

select 
    MissingId = RangeId
from 
    @Range AS R
    LEFT OUTER JOIN @Table AS T ON T.Id = R.RangeId
WHERE
    CONVERT(INT,R.RangeId) <= (SELECT MAX(CONVERT(INT,Id)) FROM @Table)
    AND T.Id IS NULL
order by MissingId
IF OBJECT_ID('tmptbl') IS NOT null
DROP TABLE tmptbl
GO
SELECT * INTO tmptbl 
FROM 
(
SELECT '1' [id]
UNION 
SELECT '3'
UNION 
SELECT '5' ) t


DECLARE @maxid INT = 0
SELECT @maxid = MAX(id) FROM tmptbl

SELECT number+1
FROM master.dbo.spt_values
WHERE number < @maxid
AND Type = 'p'    
AND NOT EXISTS ( SELECT 1
                    FROM dbo.tmptbl
                    WHERE CONVERT(INT,[id]) = (number+1))
ORDER BY number
结果是:
2,4不使用CTE,您可以使用master.dbo.spt_值技巧。不确定此表在msdb中的实际用途,但它包含我们需要的值。试试看。如果您的值大于spt_值,则将max id除以spt_值的max,并将数字+1替换为数字+1+@currentbatch*@maxsptvalues第一批为批次0。我还没有测试过它,也没有为它编写过代码,但这样的东西肯定会有用。例如,您可以在while循环中完成

IF OBJECT_ID('tmptbl') IS NOT null
DROP TABLE tmptbl
GO
SELECT * INTO tmptbl 
FROM 
(
SELECT '1' [id]
UNION 
SELECT '3'
UNION 
SELECT '5' ) t


DECLARE @maxid INT = 0
SELECT @maxid = MAX(id) FROM tmptbl

SELECT number+1
FROM master.dbo.spt_values
WHERE number < @maxid
AND Type = 'p'    
AND NOT EXISTS ( SELECT 1
                    FROM dbo.tmptbl
                    WHERE CONVERT(INT,[id]) = (number+1))
ORDER BY number
结果是:
2,4

由于您没有提到上限是什么,递归公共表表达式是什么,因此最好通过计数来实现这一点:

CREATE TABLE dbo.YourTable (ID int);

INSERT INTO dbo.YourTable (ID)
VALUES(1),(3),(5),(7),(9),(11),(13),(15),(216); --Big jump on purpose

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (SELECT MAX(ID) FROM dbo.YourTable) --Limit the tally for performance
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2, N N3) --1000 rows, add more Ns for more rows
SELECT I AS ID
FROM Tally T
     LEFT JOIN dbo.YourTable YT ON T.I = YT.ID
WHERE YT.ID IS NULL;
警告:根据对另一个答案的评论:


这是正确的方向。在我的情况下,我只得到100个数字。但是数字有8位数,而且比100位数多得多

8位数字表示您的ID值为10000000 1000多万。在一次统计中创建超过1000万行将是非常需要IO的。我强烈建议把它分批生产


编辑2:好的,对这个答案的评论最大值是9999999!这是肯定应该在问题中的信息。必须对该过程进行批处理,否则您将终止事务日志。

由于您没有提到上限是什么,以及递归公共表表达式是什么,因此最好使用计数来实现这一点:

CREATE TABLE dbo.YourTable (ID int);

INSERT INTO dbo.YourTable (ID)
VALUES(1),(3),(5),(7),(9),(11),(13),(15),(216); --Big jump on purpose

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (SELECT MAX(ID) FROM dbo.YourTable) --Limit the tally for performance
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2, N N3) --1000 rows, add more Ns for more rows
SELECT I AS ID
FROM Tally T
     LEFT JOIN dbo.YourTable YT ON T.I = YT.ID
WHERE YT.ID IS NULL;
警告:根据对另一个答案的评论:


这是正确的方向。在我的情况下,我只得到100个数字。但是数字有8位数,而且比100位数多得多

8位数字表示您的ID值为10000000 1000多万。在一次统计中创建超过1000万行将是非常需要IO的。我强烈建议把它分批生产


编辑2:好的,对这个答案的评论最大值是9999999!这是肯定应该在问题中的信息。必须对该过程进行批处理,否则将终止事务日志。

这是正确的方向。在我的情况下,我只得到100个数字。但是数字有8位数,而且比100位数多得多!那么rCTe在这里会非常慢,@comidos。您可以提高rCTE的速度,但如果您有8位数字,则需要SQL server迭代1000万次。在那个阶段的性能会更差,我显示SQL server需要一秒钟的时间来生成25000行。想象一下10000000行需要多长时间!Akash和我都向您展示了基于集合的方法这是正确的方向。在我的情况下,我只得到100个数字。但是数字有8位数,而且比100位数多得多!那么rCTe在这里会非常慢,@comidos。您可以提高rCTE的速度,但如果您有8位数字,则需要SQL server迭代1000万次。在那个阶段的性能会更差,我显示SQL server需要一秒钟的时间来生成25000行。想象一下10000000行需要多长时间!Akash和我都向您展示了基于集合的方法,正确的上限是99999999!在您的例子中,列是一个整数。在我的例子中,它是一个VarChar。我如何使它与VarChar列一起运行?为什么要将数值存储为VarChar、@comidos?但是'1'=1是真的,所以不会有问题。如果必须,可以将I的值强制转换为varchar。不过,我建议修改你的设计。请注意我的警告,@comidos。不告诉我们这将是1亿行是一个巨大的幻想。你需要批处理这个。我建议100万排。谢谢你的灵感和信息!很抱歉,没有提供有关该场景的完整信息!就在上面
限制是9999999!在您的例子中,列是一个整数。在我的例子中,它是一个VarChar。我如何使它与VarChar列一起运行?为什么要将数值存储为VarChar、@comidos?但是'1'=1是真的,所以不会有问题。如果必须,可以将I的值强制转换为varchar。不过,我建议修改你的设计。请注意我的警告,@comidos。不告诉我们这将是1亿行是一个巨大的幻想。你需要批处理这个。我建议100万排。谢谢你的灵感和信息!很抱歉,没有提供有关该场景的完整信息!检查更新的答案。您需要对类型应用必要的转换。请注意,与INT相比,varchar列上的联接速度较慢。请注意,varchar列上的联接速度与INT相比较慢。这不是真的。如果varchar的长度很小,那么最坏的情况下,速度差是微乎其微的,最好是无穷小的。但是,如果您使用的是nvarcharMAX,情况就完全不同了,但是如果您加入其中一个,则可能存在设计缺陷。请检查更新的答案。您需要对类型应用必要的转换。请注意,与INT相比,varchar列上的联接速度较慢。请注意,varchar列上的联接速度与INT相比较慢。这不是真的。如果varchar的长度很小,那么最坏的情况下,速度差是微乎其微的,最好是无穷小的。但是,如果您使用的是nvarcharMAX,情况就大不相同了,但如果您加入其中一个,则可能存在设计缺陷。