【问题标题】:How do I do "SELECT something IN (...)" with jooq?如何使用 jooq 执行“SELECT something IN (...)”?
【发布时间】:2013-09-21 13:58:07
【问题描述】:

我正在尝试对 Jooq 执行以下操作,但我一生都无法弄清楚如何正确执行此操作:

select name, id in (
  select capability_id 
   from a.capabilities_users 
   where user_id = ?) 
from a.capabilities;

基本上我想获取所有项目(功能)并了解每个项目是否适用于特定用户。似乎所有条件类型运算符(如大于或 in)只能用于 where 而不能用于 select。我想不出还有什么办法来表达这一点。

最坏的情况,我可以做一个选择计数,然后用 Java 做布尔逻辑,但我希望使用 fetchMap。

【问题讨论】:

  • 你在使用 jOOQ 的什么数据库?大多数数据库不允许在投影中使用谓词,所以我怀疑这可能是 PostgreSQL?
  • @LukasEder:该语法在 Postgres 中也是无效的。我认为 SQL 只是作为示例,它绝对不是有效的 SQL
  • @a_horse_with_no_name:适用于 PostgreSQL。 sqlfiddle.com/#!12/d41d8/1651。事实上,从jOOQ的集成测试经验来看,我可以说它可以与Derby、H2、HSQLDB、MariaDB、MySQL、PostgreSQL和SQLite一起使用
  • @LukasEder:我的立场是正确的;)谢谢你的例子,一个人真的永远不会停止学习......
  • 哇,我不知道我在做任何异国情调的事情。有趣的博文。 :-) 我正在使用 PostgreSQL 顺便说一句。爱它。也很喜欢jOOQ!

标签: java sql jooq


【解决方案1】:

根据您的数据库和模式元数据,LEFT JOIN 可能比投影中的谓词更好。您当然应该在执行计划中验证这一点。

LEFT JOIN解决这个问题:

-- NVL2 is Oracle syntax. 
-- jOOQ will emulate NVL2 using CASE, if it's not available in your database
SELECT c.name, NVL2(cu.capability_id, 1, 0)
FROM a.capabilities c
LEFT OUTER JOIN a.capabilities_users cu
  ON (c.id = cu.capability_id
  AND cu.user_id = ?)

当然,以上假设对cu(user_id, capability_id) 有一个独特的约束。然后,这将转化为 jOOQ:

Capabilities c = CAPABILITIES.as("c");
CapabilitiesUsers cu = CAPABILITIES_USERS.as("cu");

Field<String> key = c.NAME.as("key");
Field<Boolean> value = nvl2(
  CAPABILITIES_USER.CAPABILITY_ID, true, false
).as("value");

Map<String, Boolean> map =
DSL.using(configuration)
   .select(key, value)
   .from(c)
   .leftOuterJoin(cu)
   .on(c.ID.eq(cu.CAPABILITY_ID))
   .and(cu.USER_ID.eq(...))
   .fetchMap(key, value);

用投影中的谓词解决这个问题:

如果你真的更喜欢投影中的谓词,你可以试试DSL.field(Condition),它正好可以做到这一点:

Field<String> key = CAPABILITIES.NAME.as("key");
Field<Boolean> value = field(
  CAPABILITIES.ID.in(
    select(CAPABILITY_ID)
   .from(CAPABILITIES_USERS)
   .where(CAPABILITIES_USERS.USER_ID.eq(...))
  )
).as("value");

Map<String, Boolean> map =
DSL.using(configuration)
   .select(key, value)
   .from(CAPABILITIES)
   .fetchMap(key, value);

请注意,如果您使用的是符合标准的数据库,它不允许将谓词视为列,DSL.field(Condition) 将为您呈现等效的 CASE 语句。

【讨论】:

  • 在我看来,一个好的查询优化器应该能够将选择中的谓词重写为连接。 Postgresql 通常很擅长查询重写,但我会在假设它这样做之前对其运行 EXPLAIN。
  • @EricS:你可能对 PostgreSQL 擅长这一点是正确的。具体来说,如果c.IDcu.UER_ID 除了索引之外还有NOT NULL 约束,那么合并连接可能会非常快。
猜你喜欢
  • 1970-01-01
  • 2011-11-05
  • 2011-06-02
  • 2018-04-21
  • 2022-12-23
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多