2016-12-12 4 views
3

Я написал CTE для удаления нецифровых значений из набора данных, а затем получить количество числовых значений в пределах диапазона.Ошибка возврата CTE

WITH dtr 
     AS (SELECT resultlevel r 
      FROM  dbo.Result 
      WHERE DrugID = 'AMP' 
        AND ISNUMERIC(ResultLevel) = 1 
        AND AuditStamp > '1/1/2016' 
        AND DeleteFlag = 0 
     ) 
SELECT COUNT(*) 
FROM dtr 
WHERE CONVERT(INT, r) BETWEEN 50 AND 75 

Это возвращает ошибку в SMS

Msg 245, Level 16, State 1, Line 2 
Conversion failed when converting the varchar value 'PND   ' to data type int. 

Эта ошибка вполне возможно без 'DTR' запроса в КТР.

Когда я переписываю это, вместо CTR, но таблицы TEMP, он работает.

SELECT resultlevel r 
INTO #d 
FROM dbo.Result 
WHERE DrugID = 'AMP' 
     AND ISNUMERIC(ResultLevel) = 1 
     AND AuditStamp > '1/1/2016' 
     AND DeleteFlag = 0 

SELECT COUNT(*) 
FROM #d 
WHERE CONVERT(INT, r) BETWEEN 50 AND 75 

Так что мои вопросы - почему ??? Я всегда думал, что CTE походит на создание таблицы TEMP.

ТЕСТ ДАННЫЕ

if object_id('tempdb..#temp') is not null drop table #temp 

create table #temp (result char(5)) 
insert into #temp (result) values 
('1'),('A'),('>2'),('PEN ') ,('@3'),('-2'),('-33') 


;with isnum AS ( 
SELECT result 
FROM #temp 
WHERE ISNUMERIC(result) = 1) 

--Selecting from the CTE yields 1, -2, and -33 all of which can be converted to INT 
--Running the query with the where clause causes the conversion error 
SELECT 
    result, 
    ISNUMERIC(result) 
FROM isnum 
--WHERE CONVERT(INT,result) > 1 
+1

не точно - это 'CTE' не температура * стол *. Более точное описание состоит в том, что это временный * вид *. И будет вести себя как таковой. – Siyual

+1

@DMason - получите тот же результат, но я обновил дату, чтобы они были одинаковыми. – larryr

+0

изменить выбор cte на 'trim (resultlevel) r'? – xQbert

ответ

3

В SQL Server есть Logical Processing Order of the SELECT statement, который определяет, когда объекты, определенные в одном шаге сделаны доступными для положений в последующих шагах:

  1. ИЗ
  2. ON
  3. JOIN
  4. ГДЕ
  5. GROUP BY
  6. С CUBE или С ROLLUP
  7. HAVING
  8. ВЫБОР
  9. DISTINCT
  10. ORDER BY
  11. ТОП

Это как ваш запрос будет быть успешным, и ваш запрос выглядит отлично. Но иногда, SQL Server решает не следовать этому порядку, чтобы оптимизировать ваш запрос.

В вашем случае SQL Server может просто изменить/преобразовать ваш запрос в другой и выполнить функцию convert, прежде чем применять фильтрацию where isnumeric.

Если мы сделали запрос немного более сложный (но по-прежнему дает те же результаты), то SQL Server правильно выполнять код на этот раз:

;with isnum AS ( 
    SELECT result 
    FROM #temp 
    WHERE ISNUMERIC(result) = 1 
    GROUP BY result 
    HAVING MAX(result) = result 
) 
SELECT 
    result, 
    ISNUMERIC(result) 
FROM isnum 
WHERE CONVERT(INT,result) > 1; 

В вашем случае (и это то, что я делаю в таких ситуациях, когда различные типы хранятся в одном столбце), вы можете просто использовать TRY_CONVERT функции:

;with isnum AS ( 
SELECT result 
FROM #temp 
WHERE ISNUMERIC(result) = 1) 

SELECT 
    result, 
    ISNUMERIC(result) 
FROM isnum 
WHERE TRY_CONVERT(INT, result) > 1 
Смежные вопросы