Оператор CASE в предложении WHERE в SQL Server 2008

Я работаю с запросом, который содержит оператор CASE в предложении WHERE. Но SQL Server 2008 выдает некоторые ошибки при его выполнении. Может ли кто-нибудь помочь мне с правильным запросом? Вот запрос:

SELECT
    tl.storenum 'Store #', 
    co.ccnum 'FuelFirst Card #', 
    co.dtentered 'Date Entered',
    CASE st.reasonid 
        WHEN 1 THEN 'Active' 
   WHEN 2 THEN 'Not Active' 
   WHEN 0 THEN st.ccstatustypename 
   ELSE 'Unknown' 
    END 'Status',
    CASE st.ccstatustypename 
        WHEN 'Active' THEN ' ' 
   WHEN 'Not Active' THEN ' ' 
   ELSE st.ccstatustypename 
    END 'Reason',
    UPPER(REPLACE(REPLACE(co.personentered,'RT\\\\',''),'RACETRAC\\\\','')) 'Person Entered',
    co.comments 'Comments or Notes'
FROM 
    comments co
    INNER JOIN cards cc ON co.ccnum=cc.ccnum
    INNER JOIN customerinfo ci ON cc.customerinfoid=ci.customerinfoid
    INNER JOIN ccstatustype st ON st.ccstatustypeid=cc.ccstatustypeid
    INNER JOIN customerstatus cs ON cs.customerstatuscd=ci.customerstatuscd
    INNER JOIN transactionlog tl ON tl.transactionlogid=co.transactionlogid
    LEFT JOIN stores s ON s.StoreNum = tl.StoreNum
WHERE 
    CASE LEN('TestPerson')
        WHEN 0 THEN co.personentered  = co.personentered
   ELSE co.personentered LIKE '%TestPerson'
    END 
    AND cc.ccnum = CASE LEN('TestFFNum')
        WHEN 0 THEN cc.ccnum 
   ELSE 'TestFFNum' 
    END 
    AND CASE LEN('2011-01-09 11:56:29.327') 
        WHEN 0 THEN co.DTEntered = co.DTEntered 
   ELSE 
       CASE LEN('2012-01-09 11:56:29.327') 
           WHEN 0 THEN co.DTEntered >= '2011-01-09 11:56:29.327' 
      ELSE co.DTEntered BETWEEN '2011-01-09 11:56:29.327' AND '2012-01-09 11:56:29.327' 
       END 
    END
    AND tl.storenum < 699 
ORDER BY tl.StoreNum

person user1018213    schedule 09.01.2012    source источник
comment
Case выражение, а не оператор ... (выражение case возвращает значение. Оператор case используется в хранимых процедурах для условного выполнения кода.)   -  person jarlh    schedule 11.09.2018


Ответы (12)


Во-первых, оператор CASE должен быть частью выражения, а не само выражение.

Другими словами, у вас может быть:

WHERE co.DTEntered = CASE 
                          WHEN LEN('blah') = 0 
                               THEN co.DTEntered 
                          ELSE '2011-01-01' 
                     END 

Но это не сработает так, как вы их написали, например:

WHERE 
    CASE LEN('TestPerson')
        WHEN 0 THEN co.personentered  = co.personentered
   ELSE co.personentered LIKE '%TestPerson'
    END 

Возможно, вам повезет больше, если вы используете такие комбинированные операторы ИЛИ:

WHERE (
        (LEN('TestPerson') = 0 
             AND co.personentered = co.personentered
        ) 
        OR 
        (LEN('TestPerson') <> 0 
             AND co.personentered LIKE '%TestPerson')
      )

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

person Code Magician    schedule 09.01.2012
comment
КОГДА 0 ТО co.personentered = co.personentered, здесь эта проверка co.personentered = co.personentered не нужна, так как она всегда будет возвращать истину, а значение длины всегда будет положительным. Таким образом, если LEN ('TestPerson') ›0 уменьшит диапазон, необходимый для сравнения - person Satyajit; 10.11.2014
comment
как проверить, что co.personentered не равно нулю, в вариантах 1 и 2. Теперь достаточно 3-го варианта. Но я хочу знать, что ... !! - person Pugal; 01.03.2019
comment
я пробовал до сих пор where case c when 1 then (DescriptionCode is null) else descriptioncode is not null end, но показывает ошибку как Incorrect syntax near the keyword 'is'. - person Pugal; 01.03.2019

На данный момент это должно решить вашу проблему, но я должен напомнить вам, что это плохой подход:

WHERE 
            CASE LEN('TestPerson')
                WHEN 0 THEN 
                        CASE WHEN co.personentered  = co.personentered THEN 1 ELSE 0 END
                ELSE 
                        CASE WHEN co.personentered LIKE '%TestPerson' THEN 1 ELSE 0 END
            END = 1
        AND cc.ccnum = CASE LEN('TestFFNum')
                            WHEN 0 THEN cc.ccnum 
                            ELSE 'TestFFNum' 
                       END 
        AND CASE LEN('2011-01-09 11:56:29.327') 
                WHEN 0 THEN CASE WHEN co.DTEntered = co.DTEntered THEN 1 ELSE 0 END 
                ELSE 
                    CASE LEN('2012-01-09 11:56:29.327') 
                        WHEN 0 THEN 
                            CASE WHEN co.DTEntered >= '2011-01-09 11:56:29.327' THEN 1 ELSE 0 END 
                        ELSE 
                            CASE WHEN co.DTEntered BETWEEN '2011-01-09 11:56:29.327' 
                                                        AND '2012-01-09 11:56:29.327' 
                                                     THEN 1 ELSE 0 END
                    END
            END = 1
        AND tl.storenum < 699 
person Community    schedule 09.01.2012

Попробуйте следующее:

SELECT * FROM emp_master 
WHERE emp_last_name= 
CASE emp_first_name 
 WHEN 'test'    THEN 'test' 
 WHEN 'Mr name' THEN 'name'
END
person janak magotra    schedule 04.04.2013

Думаю, начало вашего запроса должно выглядеть так:

SELECT
    tl.storenum [Store #], 
    co.ccnum [FuelFirst Card #], 
    co.dtentered [Date Entered],
    CASE st.reasonid 
        WHEN 1 THEN 'Active' 
        WHEN 2 THEN 'Not Active' 
        WHEN 0 THEN st.ccstatustypename 
        ELSE 'Unknown' 
    END [Status],
    CASE st.ccstatustypename 
        WHEN 'Active' THEN ' ' 
        WHEN 'Not Active' THEN ' ' 
        ELSE st.ccstatustypename 
        END [Reason],
    UPPER(REPLACE(REPLACE(co.personentered,'RT\\\\',''),'RACETRAC\\\\','')) [Person Entered],
    co.comments [Comments or Notes]
FROM comments co
    INNER JOIN cards cc ON co.ccnum=cc.ccnum
    INNER JOIN customerinfo ci ON cc.customerinfoid=ci.customerinfoid
    INNER JOIN ccstatustype st ON st.ccstatustypeid=cc.ccstatustypeid
    INNER JOIN customerstatus cs ON cs.customerstatuscd=ci.customerstatuscd
    INNER JOIN transactionlog tl ON tl.transactionlogid=co.transactionlogid
    LEFT JOIN stores s ON s.StoreNum = tl.StoreNum
WHERE 
    CASE 
      WHEN (LEN([TestPerson]) = 0 AND co.personentered  = co.personentered) OR (LEN([TestPerson]) <> 0 AND co.personentered LIKE '%'+TestPerson) THEN 1
      ELSE 0
      END = 1
    AND 

НО

что в хвосте совсем не понятно

person Oleg Dok    schedule 09.01.2012

Там WHERE часть можно было бы записать так:

WHERE 
 (LEN('TestPerson') <> 0 OR co.personentered  = co.personentered) AND
 (LEN('TestPerson') = 0 OR co.personentered LIKE '%TestPerson') AND
 (cc.ccnum = CASE LEN('TestFFNum')
                WHEN 0 THEN cc.ccnum 
                ELSE 'TestFFNum' 
              END ) AND
 (LEN('2011-01-09 11:56:29.327') <> 0 OR co.DTEntered = co.DTEntered ) AND
 ((LEN('2011-01-09 11:56:29.327') = 0 AND LEN('2012-01-09 11:56:29.327') <> 0) OR co.DTEntered >= '2011-01-09 11:56:29.327'  ) AND
 ((LEN('2011-01-09 11:56:29.327') = 0 AND LEN('2012-01-09 11:56:29.327') = 0) OR co.DTEntered BETWEEN '2011-01-09 11:56:29.327' AND '2012-01-09 11:56:29.327'  ) AND 
 tl.storenum < 699 
person MnemosyneD    schedule 11.12.2014

Вы также можете попробовать, например, ниже. для отображения только исходящих отправлений

   SELECT shp_awb_no,shpr_ctry_cd, recvr_ctry_cd,
     CASE WHEN shpr_ctry_cd = record_ctry_cd 
     THEN "O" 
     ELSE "I" 
      END AS route
     FROM shipment_details
    WHERE record_ctry_cd = "JP"
      AND "O" = CASE WHEN shpr_ctry_cd = record_ctry_cd 
                THEN "O" 
                ELSE "I" 
                 END
person Anand    schedule 19.06.2018

Спасибо за этот вопрос, на самом деле я ищу что-то еще, что находится в запросе ниже. это может кому-то помочь.

      SELECT DISTINCT CASE WHEN OPPORTUNITY='' THEN '(BLANK)' ELSE OPPORTUNITY END
  AS OPP,LEN(OPPORTUNITY) FROM [DBO].[TBL]

Вышеупомянутый запрос должен заполнить раскрывающийся список, пустые значения которого отображаются как «(пусто)». Также, если мы передадим это значение в предложение sql where, чтобы получить пустые значения с другими значениями, я не знаю, как с этим справиться. И, наконец, придумал решение ниже, которое может кому-то помочь.

вот ,

 DECLARE @OPP TABLE (OPP VARCHAR(100))
  INSERT INTO @OPP VALUES('(BLANK)'),('UNFUNDED'),('FUNDED/NOT COMMITTED')
SELECT DISTINCT [OPPORTUNITY]
FROM [DBO].[TBL]   WHERE    (  CASE WHEN   OPPORTUNITY ='' THEN '(BLANK)' ELSE OPPORTUNITY END IN (SELECT OPP FROM @OPP))
ORDER BY 1 
person Singaravelan    schedule 06.07.2018

вот мое решение

AND CLI.PE_NOM Like '%' + ISNULL(@NomClient, CLI.PE_NOM) + '%'

Регадс Дэви

person user1780042    schedule 07.09.2016

Это работает

declare @v int=A
select * from Table_Name where XYZ=202 
and 
dbkey=(case @v  when A then 'Some Value 1'
else 'Some Value 2'
end)
person user7640374    schedule 01.03.2017

CASE LEN('TestPerson')
    WHEN 0 THEN co.personentered  = co.personentered ELSE co.personentered LIKE '%TestPerson'

Попробуйте следующее:

... and ( 
    (LEN('TestPerson') = 0 and co.personentered  = co.personentered) or
    (LEN('TestPerson') <> 0 and co.personentered LIKE '%TestPerson') ) and ...
person user1758901    schedule 12.08.2020

SELECT * from TABLE 
              WHERE 1 = CASE when TABLE.col = 100 then 1 
                     when TABLE.col = 200 then 2 else 3 END 
                  and TABLE.col2 = 'myname';

Используйте таким образом.

person Shiv    schedule 10.11.2014

person    schedule
comment
Пожалуйста, предоставьте дополнительную информацию о том, почему ваш ответ помогает решить исходный вопрос. Публикация только кода может быть немного расплывчатой ​​для пользователей с той же проблемой. - person Harry J; 25.09.2020