Есть ли способ получить запрос, который будет возвращать только результаты, основанные на значении, возвращенном оператором case? - PullRequest
0 голосов
/ 31 октября 2019

Я хотел бы получить всех сотрудников, которые были в команде в течение указанного диапазона дат. Вот запрос, который я пробовал:

SELECT *, 
CASE WHEN employee_team.joined <= '2019-05-01' 
and '2019-05-31' <= employee_team.left 
THEN 1 ELSE 0 END AS InTeamAtTime
FROM employee_team
INNER JOIN employee ON employee.id = employee_team.employee_id
WHERE InTeamAtTime = 1
ORDER BY first_name

Я получил сообщение об ошибке, говорящее ERROR: column "inteamattime" does not exist, что, я думаю, имеет смысл, поскольку этот столбец фактически не существует ни в одной из таблиц, с которыми я работаю. Но в таком случае как мне обеспечить, чтобы мой результат возвращал только тех сотрудников, которые были в команде в пределах диапазона дат?

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Для псевдонимов столбцов, которые определены в списке выбора (включая псевдонимы для выражений), вы не можете ссылаться на них в предложении WHERE по этому псевдониму, так как они «еще не существуют» в этой точке. Вы можете скопировать выражение в предложение WHERE. Но на самом деле вы можете переместить в предложение WHERE, так как нет смысла хранить его в списке выбора только для того, чтобы вернуть столбец со всеми 1.

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

select * from (
    SELECT *, 
    CASE WHEN employee_team.joined <= '2019-05-01' 
    and '2019-05-31' <= employee_team.left 
    THEN 1 ELSE 0 END AS InTeamAtTime
    FROM employee_team
    INNER JOIN employee ON employee.id = employee_team.employee_id
) foobar
WHERE InTeamAtTime = 1
ORDER BY first_name

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

0 голосов
/ 31 октября 2019

Вы не можете повторить псевдоним столбца в where. Удобным методом является использование бокового соединения:

SELECT et.*, e.*, v.InTeamAtTime
FROM employee_team et INNER JOIN
     employee e
     ON e.id = et.employee_id CROSS JOIN LATERAL
     (VALUES ( (et.joined <= '2019-05-01' AND '2019-05-31' <= et.left)::int )
     ) v_InTeamAtTime
WHERE v.InTeamAtTime = 1
ORDER BY e.first_name;

Альтернативой является подзапрос, CTE или повторение выражения.

Конечно, в вашем случае вы можете просто сделать:

SELECT et.*, e.*, 1 as InTeamAtTime
FROM employee_team et INNER JOIN
     employee e
     ON e.id = et.employee_id 
WHERE et.joined <= '2019-05-01' AND '2019-05-31' <= et.left
ORDER BY e.first_name;
...