2016-05-03 5 views
0

У меня индексированный (но не уникальный) VARCHAR поле идентификаторов Сотрудника в таблице, и в запросе мне нужно возвращать строки, которые exactly 4 numerical characters, но и более 1000.Любая причина, по которой я не должен использовать «между X и Y» в поле varchar в SQL, чтобы вернуть число?

я нашел различные вопросы, на здесь об использовании методов проверки, чтобы проверить, что поле содержит 0-9 символов или не содержит символов az и т. д., но они не связаны с этим вопросом.

фона:

У меня есть таблица с различными значениями, и образец устанавливается следующим образом:

EmployeeID 
---------- 
6745 
EMP1 
EMP2 
1874 
LTST 
5694 
0014 

То, что я хотел бы сделать, это вернуть все значения кромеEMP1, EMP2 , LTST и 0014.

Мой вопрос в том, есть ли какие-либо причины, по которым я не должен не должен использовать a Где такая статья, как where EmployeeID between '1000' and '9999'? Причиной для этого является employeeid является столбцом varchar

Если я могу это сделать, должен ли я также заказывать по идентификатору сотрудника или это не имеет значения?

+0

возврата всех значений, кроме EMP1, етр2, LTST и 0014. Что является причиной этого .Вы может сделать между а также, как вы сказали в вопросе. В чем проблема, с которой вы столкнулись – TheGameiswar

+0

@TheGameiswar мой вопрос в том, есть ли причины, по которым я не должен использовать «между» таким образом, то есть может ли он возвращать неожиданные результаты, которые не являются числовыми мы читаем их – laurencemadill

ответ

1

Выполните следующий код в качестве примера, и вы увидите, что 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; 

Идущих без где положение получает следующий поэтому SQL Сервер не принимает во внимание другие записи, чтобы быть в диапазоне от 2 до 750, когда они хранятся в виде VARCHAR .:

enter image description here

+0

Спасибо за ответ. Мой сценарий не увидит эту проблему, потому что я имею дело с символами фиксированной длины. – laurencemadill

+0

Это справедливо, но делает это, чтобы остановить такие значения, как «0001»? '0011'? и т.д? – Shaneis

2

Я считаю, что «0014» осталось бы из ряда где Clau se between '1000' and '9999', так что это причина. Возможно, between '0000' and '9999' подойдет вашим целям лучше. Просто помните, что вы все еще сортируете по тексту. Если у вас есть такие записи, как «1_99», это также будет отображаться в результатах вашего запроса с вашим заданием между предложением.

Если вы хотите, чтобы возвращать только номера 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 
+0

Да, я хочу, чтобы '0014' остался без внимания. в этом случае я хочу только значения varchar, которые на самом деле являются числовыми, и на самом деле являются 4 символами, исключая любые начальные нули. Это значения, такие как '1_99', что я буду беспокоиться о – laurencemadill

1

Если ваши реальные данные в точности совпадают с образцами данных в отношении нечисловых значений, начинающихся с буквы, вы можете использовать свой запрос для достижения желаемого результата.

Однако помните о порядке сортировки данных. Если у вас есть EmployeeId из 1ABC, он будет включен в данные, возвращаемые WHERE EmployeeID BETWEEN '1000' AND '9999'!

Ваш подход не подходит для фильтрации нечисловых значений!

Дополнительный ORDER BY влияет только на порядок результатов, он не влияет на оценку состояния WHERE.

0

Я бы сказал, что самый простой способ состоит в использовании, как:

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

позволяет сказать, у вас есть этот вход:

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]'