如何在 Knex 上使用 EXISTS 进行子查询?

Posted

技术标签:

【中文标题】如何在 Knex 上使用 EXISTS 进行子查询?【英文标题】:How can I make a subquery with EXISTS on Knex? 【发布时间】:2021-10-28 22:12:27 【问题描述】:

我正在尝试使用 knex 构建查询,但在如何使用条件 EXISTS (SELECT * FROM caregiver_patient WHERE patient_id IN (0,1)) 实现“WHERE”部分时遇到了很多麻烦。

这是关于 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 中的硬编码值,你可以随意用任何你喜欢的变量替换。

【讨论】:

感谢您的回答!另外,您知道我如何确保内部选择上的选定寄存器仅与当前寄存器相关(看护者)例如,我想要这样的东西:AND EXISTS (SELECT * FROM caregiver_patient WHERE patient_id IN (1) AND caregiver_id=caregivers.user_id);我无法使用 knex 您应该能够将另一个.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'));.

以上是关于如何在 Knex 上使用 EXISTS 进行子查询?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Knex.js 的 select 语句的子查询

EXISTS 子查询导致错误 1064

如何在此 SELECT 语句中使用 EXISTS 和子查询 [关闭]

相关子查询如何与 Exists 运算符一起使用?

如何在 SQL 子查询中使用 WHERE EXISTS?

java MySQL数据库编程 第四章 高级查询