If the user selects, then I suppose you use a variable for that.
But CASE only returns one value.
But that's good enough, since one only needs to check on 1 value.
Example:
DECLARE @stateId INT = 37;
SELECT st.STATE, l.*, st.*
FROM Pulses_tbl_Transition_log l
JOIN Pulses_mst_state st ON (st.id = l.state_id)
WHERE
(CASE
WHEN @stateId NOT IN (37, 38) AND l.state_id = @stateId THEN 1
WHEN @stateId = 37 AND l.state_id IN (1, 16, 17) THEN 2
WHEN @stateId = 38 AND l.state_id IN (11, 28) THEN 3
END) > 0;
Using OR is also an option.
DECLARE @stateId INT = 37;
SELECT st.STATE, l.*, st.*
FROM Pulses_tbl_Transition_log l
JOIN Pulses_mst_state st ON (st.id = l.state_id)
WHERE
(
(l.state_id = @stateId AND @stateId NOT IN (37, 38)) OR
(l.state_id IN (1, 16, 17) AND @stateId = 37) OR
(l.state_id IN (11, 28) AND @stateId = 38)
);
Just beware that AND's are evaluated before the OR's. Reference
So using parentesis helps to avoid logical misunderstandings.
For example, guess what the result will be of this example SQL:
select
(case when 1=1 OR 2=2 AND 3=0 then 'true' else 'false' end) as r1,
(case when 1=1 OR (2=2 AND 3=0) then 'true' else 'false' end) as r2,
(case when (1=1 OR 2=2) AND 3=0 then 'true' else 'false' end) as r3;
If there's an index on the state_id then for performance reasons it might be worth it to use a Dynamic SQL instead. And change the criteria in the dynamic SQL statement depending on the value of the variable.