Вам нужно префикс выражение, которое нужно инвертировать с помощью ~
, поэтому ~ and_(...)
.
Обратите внимание, что существуют операторы и функции для всех операторов логической логики. ~
также доступно как not_()
функция , и, аналогично, and_()
можно выразить с помощью &
, а or_()
можно выразить с помощью |
. Я бы придерживался одного стиля или другого, а не обоих.
Таким образом, ваши требования могут быть выражены как
and_(
and_(
Jobs.candidate_id == candidate_id,
Jobs.interview_type == 'EVALUATION',
Jobs.disposition_date < datetime.now()-timedelta(days=1)
),
not_(
and_(
not_(Jobs.candidate_id == candidate_id),
Jobs.interview_type == 'IN_HOUSE',
Jobs.disposition_date > '2017-01-01'
)
)
)
или как
(
(
(Jobs.candidate_id == candidate_id)
& (Jobs.interview_type == 'EVALUATION')
& (Jobs.disposition_date < datetime.now()-timedelta(days=1))
)
& (
~ (
~ (Jobs.candidate_id == candidate_id)
& (Jobs.interview_type == 'IN_HOUSE')
& (Jobs.disposition_date > '2017-01-01')
)
)
)
Поскольку операторы ~
, &
и |
имеют меньший приоритет, чем операторы сравнения , вам необходимо использовать (...)
скобки вокруг каждого из приведенных выше тестов, чтобы убедиться, что операторы применяется ко всем column == value
и column < value
тестам.
Я не уверен на 100%, что вы хотели использовать not_(Jobs.candidate_id == candidate_id)
, но если бы вы это сделали, то я просто использовал бы !=
там, так что Jobs.candidate_id != candidate_id
и отбросил бы условие not_()
в этом тесте.
Далее, запрос в любом случае, вероятно, не даст правильных результатов. Он скажет вам, если есть 1 или более строк, которые соответствуют вашим критериям, таким образом, строки, где совпадает идентификатор кандидата, и есть конкретные условия для типа интервью и даты проведения. То, что он не сделает, скажет вам, если есть только таких строк, которые соответствуют. Так что, если есть такие строки:
candidate_id | disposition_date | interview_type
---------------|-------------------|-----------------
42 | 2018-01-01 | EVALUATION
42 | 2018-01-02 | IN_HOUSE
тогда вы получите True
, потому что есть 1 строка, соответствующая вашим критериям. Строка IN_HOUSE
отфильтрована. Вы не получите False
здесь, потому что не имеет значения, что другая строка существует для фильтра.
В этом случае вы хотите использовать логическую логику выражения NOT
в отдельных предложениях EXISTS
, , а не в условиях , поэтому наличие второй строки приводит к результату False
, противостоящему True
для другой строки:
SELECT id
FROM jobs
WHERE
EXISTS(candidate_id = ? AND interview_type = ? AND disposition_date < ?)
AND NOT EXISTS(candidate_id = ? AND interview_type = ? AND disposition_date > ?)
поэтому создайте два отдельных существующих запроса :
candidate = db_session.query(Jobs).filter(Jobs.candidate_id == candidate_id)
has_evaluation = (
candidate
.filter(Jobs.interview_type == 'EVALUATION')
.filter(Jobs.disposition_date < datetime.now() - timedelta(days=1))
)
has_inhouse = (
candidate
.filter(Jobs.interview_type == 'IN_HOUSE')
.filter(Jobs.disposition_date > '2017-01-01')
)
recent_oa = (
db_session.query(Jobs.id)
.filter(has_evaluation.exists())
.filter(not_(has_inhouse.exists())) # or .filter(~has_inhouse.exists())
.scalar()
)
Используется метод Query.exists()
для создания отдельных EXISTS
условий.