Есть ли способ использовать функцию Case с типом данных nvarchar при сравнении двух столбцов?

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я пытаюсь извлечь значения, которые удовлетворяют условию case , условие таково

  • Случай, когда tr.value < tr.PanicMin затем возвращает tr.value

  • Случай, когда tr.value > tr.PanicMax затем возвращает tr.value

но я получаю сообщение об ошибке «Ошибка преобразования типа данных nvarchar в числовой», поскольку значения в трех столбцах (tr.panicMin, tr.PanicMax, Tr.value) не являются числовыми, исходный запрос, используемый перед добавлением функции case, является:

 SELECT SP.Specialisation, TSP.SpecimenName,T.Name as Test_Name,TR.Value,TR.PanicMin ,tr.PanicMax , PA.RegCode AS UHID, TT.DoneAt AS COL_DATE, TT1.DoneAt AS ACK_DATE, TT2.DoneAt AS VER_DATE, TT2.DoneBy,
(CAST((DATEDIFF(minute, TT1.DoneAt, TT2.DoneAt))/60 AS VARCHAR) ' H:'                                 
  CAST((DATEDIFF(minute,TT1.DoneAt,TT2.DoneAt))%60 AS VARCHAR) ' M') AS TAT,
(CASE WHEN TOI.TestID IN (2160, 2878, 956, 1000, 1002, 932, 934) AND ((DATEDIFF(minute, TT1.DoneAt, TT2.DoneAt)) > 60) THEN 'WITHOUT TAT'
WHEN TOI.TestID IN (991, 941, 942, 943, 2396) AND ((DATEDIFF(minute, TT1.DoneAt, TT2.DoneAt)) > 15) THEN 'WITHOUT TAT'
WHEN TT2.DoneAt IS NULL THEN NULL
ELSE 'WITHIN TAT' END) AS TAT_STAT 
FROM v_dbNxGtestorderitems TOI
INNER JOIN V_TestSpecimen TSP ON TSP.TestID = TOI.TestID
INNER JOIN v_dbNxgtestorders TSO ON TSO.TestOrderID = TOI.TestOrderID AND TSO.OrderTypeID = 15
INNER JOIN v_dbSpecializations SP ON SP.SpecialiseID = TOI.SpecialiseID
INNER JOIN v_dbPatientAdmissions PA ON PA.AdmissionID = TOI.AdmissionID
  join v_dbtestresults tr on tr.TestOrderID=TOI.TestOrderID
  join v_Tests t on t.TestId=tr.TestID
  join v_dbTestComponents tc on tc.TestID=tr.TestID
  join v_dbComponents c on c.ComponentID=tr.ComponentID
CROSS apply   (select top 1  TestOrderID, TestOrderItemID, DoneAt  from  v_dbtesttasks
where TestOrderID=toi.TestOrderID and    TestOrderItemID=toi.TestOrderItemID and taskStatusid=3
Order  by DoneAt desc  )  tt
CROSS apply   (select top 1  TestOrderID, TestOrderItemID, DoneAt  from  v_dbtesttasks
where TestOrderID=toi.TestOrderID and    TestOrderItemID=toi.TestOrderItemID and taskStatusid=4
Order  by DoneAt desc  )  tt1
outer  apply   (select top 1  TestOrderID, TestOrderItemID, DoneAt, SD.Name AS DoneBy from  v_dbtesttasks TTS
INNER JOIN v_dbSecurityIds SD ON SD.SID = TTS.DoneBy
where TestOrderID=toi.TestOrderID and    TestOrderItemID=toi.TestOrderItemID and taskStatusid=8
order  by DoneAt desc  )  tt2
WHERE TOI.TestID in (932, 934, 941, 942, 943, 991, 1000, 1002, 2396, 2878, 2160) AND TSO.OrderDate > '2019-01-01' AND TSO.OrderDate < DATEADD(DAY, 1, '2019-01-10') 
  

и вывод запроса
введите описание изображения здесь

Комментарии:

1. почему бы вам не использовать функцию ПРИВЕДЕНИЯ?

2. лучшее решение — не хранить числовые данные в (n) столбце varchar

3. Я использовал функцию приведения к numeric и nvarchar и все еще получаю ту же ошибку

4. Какая версия SQL Server? Пожалуйста, всегда включайте эту информацию.

5. Вы всегда можете попробовать ISNUMERIC(), чтобы увидеть, какие значения не являются числовыми в этих столбцах. Как только вы узнаете, каковы значения проблемы, вы можете обратиться к ним или почему они помещаются туда в первую очередь.

Ответ №1:

В SQL Server 2012 и выше вы можете использовать:

 CASE WHEN TRY_CONVERT(float, tr.value) < TRY_CONVERT(float, tr.PanicMin)
       OR TRY_CONVERT(float, tr.value) > TRY_CONVERT(float, tr.PanicMax)
  THEN tr.value END
  

В более старых версиях один подход требует, чтобы вы полагались на своего рода непрочную функцию и вложенные CASE выражения:

 CASE 
  WHEN ISNUMERIC(tr.PanicMin) = 1 
   AND ISNUMERIC(tr.PanicMax) = 1
   AND ISNUMERIC(tr.value) = 1 
  THEN 
    CASE 
      WHEN CONVERT(float, tr.value) < CONVERT(float, tr.PanicMan)
           OR CONVERT(float, tr.value) > CONVERT(floar, tr.PanixMax)
      THEN tr.value
    END
END
  

Ответ №2:

Вы могли бы попробовать преобразовать для передачи из вашей строки с числовым содержимым в формате float

  convert(float,'9.0')
  

в вашем случае

 convert(float, tr.PanicMin)