Sql server 我为什么不';t使用;在X和Y之间“;在SQL中的varchar字段上返回数字?

Sql server 我为什么不';t使用;在X和Y之间“;在SQL中的varchar字段上返回数字?,sql-server,where,where-clause,between,Sql Server,Where,Where Clause,Between,我在一个表中有一个索引(但不是唯一的)员工ID的varchar字段,在一个查询中,我需要返回正好是4个数字字符但也超过1000的行 我在这里发现了关于使用验证方法检查字段是否包含0-9个字符,或不包含a-z字符等的各种问题,但这些问题与此问题无关 背景: 我得到了一个具有各种值的表,样本集如下: EmployeeID ---------- 6745 EMP1 EMP2 1874 LTST 5694 0014 我想做的是返回除EMP1、EMP2、LTST和0014之外的所有值 我的问题是,有什么

我在一个表中有一个索引(但不是唯一的)员工ID的varchar字段,在一个查询中,我需要返回正好是4个数字字符但也超过1000的行

我在这里发现了关于使用验证方法检查字段是否包含0-9个字符,或不包含a-z字符等的各种问题,但这些问题与此问题无关

背景:

我得到了一个具有各种值的表,样本集如下:

EmployeeID
----------
6745
EMP1
EMP2
1874
LTST
5694
0014
我想做的是返回除
EMP1
EMP2
LTST
0014
之外的所有值

我的问题是,有什么理由我不应该使用Where子句,比如
Where EmployeeID介于“1000”和“9999”之间
?之所以使用employeeid,是因为它是一个varchar列


如果我能做到这一点,我是否也应该按员工ID订购,或者这无关紧要?

运行以下代码作为示例,您将看到SQL Server不会将
INT
视为存储为
VARCHAR
的整数:

WITH    IntsAsVars
AS      (
        SELECT  var = '1000',
                int = 1000
        UNION   ALL 
        SELECT  var = '100',
                int = 100
        UNION   ALL 
        SELECT  var = '9999',
                int = 999
        UNION   ALL 
        SELECT  var = '99',
                int = 99
        UNION   ALL 
        SELECT  var = '750',
                int = 750
        UNION   ALL 
        SELECT  var = '10',
                int = 10
        UNION   ALL 
        SELECT  var = '2',
                int = 2
        )
SELECT  *
FROM    IntsAsVars
--WHERE var BETWEEN '2' AND '750'   
/* should return 2, 10, 99, 100 & 750 if it works like INT
   but does it? */
ORDER   BY
        --var ASC,  
        int ASC;

在没有WHERE子句的情况下运行它,因此SQLServer在被存储为VARCHAR时不认为其他记录在2到750之间:


运行以下代码作为示例,您将看到SQL Server不会将
INT
视为存储为
VARCHAR
的整数:

WITH    IntsAsVars
AS      (
        SELECT  var = '1000',
                int = 1000
        UNION   ALL 
        SELECT  var = '100',
                int = 100
        UNION   ALL 
        SELECT  var = '9999',
                int = 999
        UNION   ALL 
        SELECT  var = '99',
                int = 99
        UNION   ALL 
        SELECT  var = '750',
                int = 750
        UNION   ALL 
        SELECT  var = '10',
                int = 10
        UNION   ALL 
        SELECT  var = '2',
                int = 2
        )
SELECT  *
FROM    IntsAsVars
--WHERE var BETWEEN '2' AND '750'   
/* should return 2, 10, 99, 100 & 750 if it works like INT
   but does it? */
ORDER   BY
        --var ASC,  
        int ASC;

在没有WHERE子句的情况下运行它,因此SQLServer在被存储为VARCHAR时不认为其他记录在2到750之间:

我相信在'1000'和'9999'之间的where子句
中会省略“0014”,所以这是一个原因。也许介于“0000”和“9999”之间的
更适合您的目的。请记住,您仍然在根据文本进行排序。如果您有任何类似“1_99”的条目,这也会显示在查询结果中,并带有给定的between子句

如果您希望只返回不包括前导零的4个字符的数字,那么以下加法就足够了:

WHERE EmployeeID BETWEEN '1000' AND '9999' AND TRY_CAST(EmployeeID As int) IS NOT NULL
…或者更直观地说:

WHERE TRY_CAST(EmployeeID As int) BETWEEN 1000 AND 9999
我相信在'1000'和'9999'之间的where子句
中会省略“0014”,所以这是一个原因。也许介于“0000”和“9999”之间的
更适合您的目的。请记住,您仍然在根据文本进行排序。如果您有任何类似“1_99”的条目,这也会显示在查询结果中,并带有给定的between子句

如果您希望只返回不包括前导零的4个字符的数字,那么以下加法就足够了:

WHERE EmployeeID BETWEEN '1000' AND '9999' AND TRY_CAST(EmployeeID As int) IS NOT NULL
…或者更直观地说:

WHERE TRY_CAST(EmployeeID As int) BETWEEN 1000 AND 9999

如果实际数据与以字母开头的非数字值的示例数据完全相同,则可以使用查询来获得所需的结果

但是,请注意数据的排序顺序。如果您的EmployeeId为
1ABC
,它将包含在
返回的数据中,其中EmployeeId介于“1000”和“9999”之间。

您的方法不适合过滤非数值


附加的
ORDER BY
仅影响结果的顺序,它对
WHERE
条件的计算没有影响。

如果实际数据与以字母开头的非数字值的样本数据完全相同,则可以使用查询来获得所需的结果

但是,请注意数据的排序顺序。如果您的EmployeeId为
1ABC
,它将包含在
返回的数据中,其中EmployeeId介于“1000”和“9999”之间。

您的方法不适合过滤非数值


附加的
排序依据
仅影响结果的顺序,它对
WHERE
条件的评估没有影响。

我想说最简单的方法是使用如下方法:

select * from yourtable
where EmployeeID like '[1-9][0-9][0-9][0-9]'

我想说,最简单的方法是使用:

select * from yourtable
where EmployeeID like '[1-9][0-9][0-9][0-9]'

假设您有以下输入:

IF OBJECT_ID('tempdb..#test') IS NOT NULL
    DROP TABLE #test

CREATE TABLE #test
(
    EmployeeID VARCHAR(255)
)

CREATE CLUSTERED INDEX CIX_test_EmployeeID ON #test(EmployeeID)

INSERT INTO #test
VALUES 
('6745'),
('EMP1'),
('EMP2'),
('1874'),
('LTST'),
('5694'),
('1000'),
('9999'),
('10L'),
('187'),
('9X9'),
('7est'),
('1ok'),
('0_o'),
('0014');
您的语句还将返回“1ok”、“187”、“10L”等。 既然您提到您的employeeID有一个固定的长度,您可以使用如下内容:

SELECT *
FROM #test
WHERE EmployeeID LIKE '[1-9][0-9][0-9][0-9]'

假设您有以下输入:

IF OBJECT_ID('tempdb..#test') IS NOT NULL
    DROP TABLE #test

CREATE TABLE #test
(
    EmployeeID VARCHAR(255)
)

CREATE CLUSTERED INDEX CIX_test_EmployeeID ON #test(EmployeeID)

INSERT INTO #test
VALUES 
('6745'),
('EMP1'),
('EMP2'),
('1874'),
('LTST'),
('5694'),
('1000'),
('9999'),
('10L'),
('187'),
('9X9'),
('7est'),
('1ok'),
('0_o'),
('0014');
您的语句还将返回“1ok”、“187”、“10L”等。 既然您提到您的employeeID有一个固定的长度,您可以使用如下内容:

SELECT *
FROM #test
WHERE EmployeeID LIKE '[1-9][0-9][0-9][0-9]'

返回除EMP1、EMP2、LTST和0014之外的所有值。这是什么原因?你可以像你在问题中说的那样做中间人。你的问题是什么facing@TheGameiswar我的问题是,是否有理由不以这种方式使用“between”,也就是说,当我们读取它们时,它是否会返回非数字的意外结果?返回除EMP1、EMP2、LTST和0014之外的所有值。这是什么原因?你可以像你在问题中说的那样做中间人。你的问题是什么facing@TheGameiswar我的问题是,是否有理由我不应该以这种方式使用“between”(介于两者之间),即它是否会在我们读取它们时返回非数字的意外结果是的,我希望
0014
被忽略。在本例中,我只希望varchar值实际上是数字,实际上是4个字符,不包括任何前导零。我担心的是像
1_99
这样的值。是的,我希望
0014
被忽略。在本例中,我只希望varchar值实际上是数字,实际上是4个字符,不包括任何前导零。我担心的是像
1\u99
这样的值,谢谢你的回答。我的场景不会看到这个问题,因为我也处理固定长度的字符。这很公平,但这会阻止像“0001”这样的值吗?'0011'? 等等?谢谢你的回答。我的场景不会看到这个问题,因为我处理的是固定长度字符