#javascript #sql #node.js #typescript #knex.js
Вопрос:
Я пытаюсь построить запрос с помощью knex, но у меня много проблем с тем, как реализовать часть «ГДЕ» с условием EXISTS (SELECT * FROM caregiver_patient WHERE patient_id IN (0,1))
.
Вот исходный запрос на SQL:
SELECT * FROM users
JOIN caregivers ON users.id = caregivers.user_id
JOIN caregiver_schedule ON caregivers.id = caregiver_schedule.caregiver_id
JOIN caregiver_patient ON caregivers.id = caregiver_patient.caregiver_id
JOIN patients ON caregiver_patient.patient_id = patients.id
WHERE caregiver_schedule.week_day = 2
AND caregiver_schedule.from_time <= 1320
AND caregiver_schedule.to_time > 1320
AND EXISTS (SELECT * FROM caregiver_patient WHERE patient_id IN (0,1));
И вот код, который у меня есть до сих пор с Knex:
const caregivers = await db("caregivers")
.whereExists(function () {
this.select("caregiver_schedule.*")
.from("caregiver_schedule")
.whereRaw("`caregiver_schedule`.`caregiver_id` = `caregivers`.`id`")
.whereRaw("`caregiver_schedule`.`week_day` = ??", [Number(week_day)])
.whereRaw("`caregiver_schedule`.`from_time` <= ??", [timeInMinutes])
.whereRaw("`caregiver_schedule`.`to_time` > ??", [timeInMinutes]);
})
.join("users", "caregivers.user_id", "=", "users.id")
.join("patients", "caregiver_patient.patient_id", "=", "patients.id")
.select([
"caregivers.*",
"users.*",
"caregiver_schedule.*",
"patients.*",
]);
Все числа в исходном запросе должны быть переменными. Числа внутри IN
должны быть массивом.
Кто-нибудь может помочь мне закончить создание этого запроса на Knex?
Ответ №1:
Приведенный вами пример запроса knex на самом деле не очень похож на исходный SQL-запрос, вот как выглядел бы ваш исходный SQL-запрос, если бы вы хотели преобразовать его в запрос knex:
const result = await db('users')
.innerJoin('caregivers', 'users.id', 'caregivers.user_id')
.innerJoin('caregiver_schedule', 'caregivers.id' 'caregiver_schedule.caregiver_id')
.innerJoin('caregiver_patient', 'caregivers.id', 'caregiver_patient.caregiver_id')
.innerJoin('patients', 'caregiver_patient.patient_id', 'patients.id')
.where('caregiver_schedule.week_day', Number(week_day))
.where('caregiver_schedule.from_time', '<=', timeInMinutes)
.where('caregiver_schedule.to_time', '>', timeInMinutes)
.whereExists(function() {
this.select('*')
.from('caregiver_patient')
.whereIn('patient_id', [0,1]);
})
.select('*');
Это предполагает, что db
переменная является вашим соединением knex. Мне также пришлось угадать переменные, которые вы хотели использовать для замены жестко закодированных значений в исходном SQL, не стесняйтесь заменять переменные любыми, которые вам нравятся.
Комментарии:
1. Спасибо вам за ответ! Кроме того, знаете ли вы, как я могу убедиться, что выбранные регистры во внутреннем выборе связаны только с текущим регистром (воспитателем) Например, я хотел чего-то подобного:
AND EXISTS (SELECT * FROM caregiver_patient WHERE patient_id IN (1) AND caregiver_id=caregivers.user_id);
я не могу сделать это с knex2. Вы должны просто иметь возможность вставить другой
.where
запрос в указанный выше запрос внутриwhereExists
функции, с той лишь разницей, что, когда вы хотите ссылаться на другой столбец вwhere
предложении, вам нужно использовать немного другой синтаксис, иначе он попытается сопоставить его со строковым литералом"caregivers.user_id"
, а не со столбцом. Есть два способа сделать это, первый-использовать.ref
, например.where('caregiver_id', knex.ref('caregivers.user_id'));
, другой вариант-использовать позиционные аргументы и, например, knex.raw.where('caregiver_id', knex.raw('??', 'caregivers.user_id'));
.