【问题标题】:jOOq Key Produces Bad QueryjOOq 密钥产生错误查询
【发布时间】:2016-04-19 18:19:31
【问题描述】:

如果我们两次引用 Keys 常量,我似乎在 jOOq 3.7.3 中有一个错误。举个例子:

    final Select<Record10<BigDecimal, String, String, String, Timestamp, BigDecimal, BigDecimal, String, String, String>> query = readContext
            .select(li.LIBRARY_ITEM_ID,
                    li.TITLE,
                    li.DETAILED_DESCRIPTION,
                    li.URL,
                    li.CREATE_DATE,
                    li.PORTFOLIO_ID,
                    li.ORGANIZATION_ID,
                    DSL.decode()
                            .when(o_aux_lead_center.ORGANIZATION_ID.isNotNull(),
                                    o_aux_lead_center.ORGANIZATION_NAME)
                            .otherwise(o_lead_center.ORGANIZATION_NAME).as(ORG_NAME),
                    DSL.decode()
                            .when(o_aux_lead_center.ORGANIZATION_ID.isNotNull(),
                                    o_aux_lead_center.ACRONYM).otherwise(o_lead_center.ACRONYM)
                            .as(ORG_ACRONYM), o_resp_mission_dir.ORGANIZATION_NAME)
            .from(li
                    .join(lc.join(lct).onKey(Keys.LC_LCT___FK)
                            .and(lct.CODE_TYPE.equal(LkuCodeTypeLookup.LIBRARY_ITEM_TYPE)))
                    .onKey(Keys.LI_LC_LITI___FK)
                    .and(lc.CODE.equal(LkuCodeLookup.LIBRARY_ITEM_TYPE_NEWS_STORY))
                    // The Portfolio
                    .join(p.join(lc).onKey(Keys.P_LC_ATI___FK)
                            .and(lc.CODE.in(LkuCodeLookup.PORTFOLIO_ACTIVITY_TYPE_TECHNOLOGY))
                            .join(lct).onKey(Keys.LC_LCT___FK)
                            .and(lct.CODE_TYPE.equal(LkuCodeTypeLookup.ACTIVITY_TYPE)))
                    .on(li.PORTFOLIO_ID.equal(p.PORTFOLIO_ID))
                    // The CO for the Portfolio associated with the library item
                    .join(co
                            .join(lc.join(lct).onKey(Keys.LC_LCT___FK)
                                    .and(lct.CODE_TYPE.equal(LkuCodeTypeLookup.OBJECT_TYPE)))
                            .onKey(Keys.CO_LC_OTI___FK)
                            .and(lc.CODE.equal(LkuCodeLookup.OBJECTTYPE_PORTFOLIOS))
                            .and(limitByRelease).join(tu).on(tu.USER_ID.equal(uid))
                            .and(limitBySensitivities))
                    .on(p.PORTFOLIO_ID.equal(co.OBJECT_ID))
                    // The CO for the Library Item
                    .join(co
                            .join(lc.join(lct).onKey(Keys.LC_LCT___FK)
                                    .and(lct.CODE_TYPE.equal(LkuCodeTypeLookup.OBJECT_TYPE)))
                            .onKey(Keys.CO_LC_OTI___FK)
                            .and(lc.CODE.equal(LkuCodeLookup.OBJECTTYPE_LIBRARY_ITEMS))
                            .andExists(
                                    readContext
                                            .selectFrom(cos)
                                            .where(cos.CORE_OBJECT_ID.equal(co.CORE_OBJECT_ID))
                                            .and(cos.SECTION
                                                    .equal(BigDecimal
                                                            .valueOf(AccessControlConstants.CORE_OBJECT_CHAR_ARRAY_SELF))
                                                    .and(cos.SENSITIVITIES.equal(BigDecimal.ZERO)))))
                    .on(li.LIBRARY_ITEM_ID.equal(co.OBJECT_ID)))
            // The Responsible Mission Directorate
            .leftOuterJoin(
                    po
                            .join(o_resp_mission_dir)
                            .on(po.ORGANIZATION_ID.equal(o_resp_mission_dir.ORGANIZATION_ID))
                            .join(lc)
                            .onKey(Keys.PO_LC_ATI___FK)
                            .and(lc.CODE
                                    .equal(LkuCodeLookup.ASSOCIATIONTYPE_RESPONSIBLE_MISSION_DIRECTORATE))
                            .join(lct)
                            .onKey(Keys.LC_LCT___FK)
                            .and(lct.CODE_TYPE
                                    .equal(LkuCodeTypeLookup.PORTFOLIO_ORGANIZATION_ASSOCIATION_TYPE)))
            .onKey(Keys.PO_P___FK)
            // The Portfolio Organizations
            .leftOuterJoin(
                    po
                            // Add in the organization data
                            .join(o_lead_center.leftOuterJoin(o_aux_lead_center).on(
                                    o_lead_center.REPLACEMENT_ORGANIZATION_ID.equal(
                                            o_aux_lead_center.ORGANIZATION_ID).and(
                                            o_lead_center.IS_ACTIVE.equal(byteZero))))
                            .on(po.ORGANIZATION_ID.equal(o_lead_center.ORGANIZATION_ID))
                            .join(lc)
                            .onKey(Keys.PO_LC_ATI___FK)
                            .and(lc.CODE.equal(LkuCodeLookup.ASSOCIATIONTYPE_LEAD_CENTER))
                            .join(lct)
                            .onKey(Keys.LC_LCT___FK)
                            .and(lct.CODE_TYPE
                                    .equal(LkuCodeTypeLookup.PORTFOLIO_ORGANIZATION_ASSOCIATION_TYPE)))
            .onKey(Keys.PO_P___FK)
            .orderBy(
                    DSL.decode().when(li.UPDATE_DATE.isNull(), li.CREATE_DATE)
                            .otherwise(li.UPDATE_DATE).desc());

这会生成错误的 SQL 查询 (Oracle 12C):

select 
  "SCHEMA_A"."LIBRARY_ITEMS"."LIBRARY_ITEM_ID", 
  "SCHEMA_A"."LIBRARY_ITEMS"."TITLE", 
  "SCHEMA_A"."LIBRARY_ITEMS"."DETAILED_DESCRIPTION", 
  "SCHEMA_A"."LIBRARY_ITEMS"."URL", 
  "SCHEMA_A"."LIBRARY_ITEMS"."CREATE_DATE", 
  "SCHEMA_A"."LIBRARY_ITEMS"."LIBRARY_ID", 
  "SCHEMA_A"."LIBRARY_ITEMS"."ORGANIZATION_ID", 
  case when "AuxLeadCenter"."ORGANIZATION_ID" is not null then "AuxLeadCenter"."ORGANIZATION_NAME"
       else "LeadCenter"."ORGANIZATION_NAME"
  end "ORG_NAME", 
  case when "AuxLeadCenter"."ORGANIZATION_ID" is not null then "AuxLeadCenter"."ACRONYM"
       else "LeadCenter"."ACRONYM"
  end "ORG_ACRONYM", 
  "RespMissionDir"."ORGANIZATION_NAME"
from "SCHEMA_A"."LIBRARY_ITEMS"
  join (
    "SCHEMA_A"."LKU_CODE"
      join "SCHEMA_A"."LKU_CODE_TYPE"
      on (
        "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
        and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'LIBRARY_ITEM_TYPE'
      )
  )
  on (
    "SCHEMA_A"."LIBRARY_ITEMS"."LIBRARY_ITEM_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
    and "SCHEMA_A"."LKU_CODE"."CODE" = 'NEWS_STORY'
  )
  join (
    "SCHEMA_A"."LIBRARY"
      join "SCHEMA_A"."LKU_CODE"
      on (
        "SCHEMA_A"."LIBRARY"."ACTIVITY_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
        and "SCHEMA_A"."LKU_CODE"."CODE" in (
          'MISSION_WITH_TECHNOLOGY', 'TECHNOLOGY_ONLY'
        )
      )
      join "SCHEMA_A"."LKU_CODE_TYPE"
      on (
        "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
        and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'ACTIVITY_TYPE'
      )
  )
  on "SCHEMA_A"."LIBRARY_ITEMS"."LIBRARY_ID" = "SCHEMA_A"."LIBRARY"."LIBRARY_ID"
  join (
    "SCHEMA_A"."AC"
      join (
        "SCHEMA_A"."LKU_CODE"
          join "SCHEMA_A"."LKU_CODE_TYPE"
          on (
            "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
            and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'OBJECT_TYPE'
          )
      )
      on (
        "SCHEMA_A"."AC"."OBJECT_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
        and "SCHEMA_A"."LKU_CODE"."CODE" = 'PORTFOLIOS'
        and exists (
          select 
            "SCHEMA_A"."AC_RELEASE_TYPES"."AC_ID", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."SECTION", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."RELEASE_TYPE", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."CREATE_DATE", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."CREATED_BY", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."UPDATE_DATE", 
            "SCHEMA_A"."AC_RELEASE_TYPES"."UPDATED_BY"
          from "SCHEMA_A"."AC_RELEASE_TYPES"
          where (
            "SCHEMA_A"."AC"."AC_ID" = "SCHEMA_A"."AC_RELEASE_TYPES"."AC_ID"
            and "SCHEMA_A"."AC_RELEASE_TYPES"."SECTION" = 1
            and "SCHEMA_A"."AC_RELEASE_TYPES"."RELEASE_TYPE" in (
              6, 7
            )
          )
        )
      )
      join "SCHEMA_A"."TP_USERS"
      on (
        "SCHEMA_A"."TP_USERS"."USER_ID" = 456920
        and exists (
          select 
            "SCHEMA_A"."AC_SENSITIVITIES"."AC_ID", 
            "SCHEMA_A"."AC_SENSITIVITIES"."SECTION", 
            "SCHEMA_A"."AC_SENSITIVITIES"."SENSITIVITIES", 
            "SCHEMA_A"."AC_SENSITIVITIES"."CREATE_DATE", 
            "SCHEMA_A"."AC_SENSITIVITIES"."CREATED_BY", 
            "SCHEMA_A"."AC_SENSITIVITIES"."UPDATE_DATE", 
            "SCHEMA_A"."AC_SENSITIVITIES"."UPDATED_BY"
          from "SCHEMA_A"."AC_SENSITIVITIES"
          where (
            "SCHEMA_A"."AC"."AC_ID" = "SCHEMA_A"."AC_SENSITIVITIES"."AC_ID"
            and "SCHEMA_A"."AC_SENSITIVITIES"."SECTION" = 0
            and bitand(
              "SCHEMA_A"."TP_USERS"."SENSITIVITIES", 
              "SCHEMA_A"."AC_SENSITIVITIES"."SENSITIVITIES") = "SCHEMA_A"."AC_SENSITIVITIES"."SENSITIVITIES"
          )
        )
      )
  )
  on "SCHEMA_A"."LIBRARY"."LIBRARY_ID" = "SCHEMA_A"."AC"."OBJECT_ID"
  join (
    "SCHEMA_A"."AC"
      join (
        "SCHEMA_A"."LKU_CODE"
          join "SCHEMA_A"."LKU_CODE_TYPE"
          on (
            "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
            and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'OBJECT_TYPE'
          )
      )
      on (
        "SCHEMA_A"."AC"."OBJECT_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
        and "SCHEMA_A"."LKU_CODE"."CODE" = 'LIBRARY_ITEMS'
        and exists (
          select 
            "SCHEMA_A"."AC_SENSITIVITIES"."AC_ID", 
            "SCHEMA_A"."AC_SENSITIVITIES"."SECTION", 
            "SCHEMA_A"."AC_SENSITIVITIES"."SENSITIVITIES", 
            "SCHEMA_A"."AC_SENSITIVITIES"."CREATE_DATE", 
            "SCHEMA_A"."AC_SENSITIVITIES"."CREATED_BY", 
            "SCHEMA_A"."AC_SENSITIVITIES"."UPDATE_DATE", 
            "SCHEMA_A"."AC_SENSITIVITIES"."UPDATED_BY"
          from "SCHEMA_A"."AC_SENSITIVITIES"
          where (
            "SCHEMA_A"."AC_SENSITIVITIES"."AC_ID" = "SCHEMA_A"."AC"."AC_ID"
            and "SCHEMA_A"."AC_SENSITIVITIES"."SECTION" = 0
            and "SCHEMA_A"."AC_SENSITIVITIES"."SENSITIVITIES" = 0
          )
        )
      )
  )
  on "SCHEMA_A"."LIBRARY_ITEMS"."LIBRARY_ITEM_ID" = "SCHEMA_A"."AC"."OBJECT_ID"
  left outer join (
    "SCHEMA_A"."LIBRARY_ORGANIZATIONS"
      join "SCHEMA_A"."ORGANIZATIONS" "RespMissionDir"
      on "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."ORGANIZATION_ID" = "RespMissionDir"."ORGANIZATION_ID"
      join "SCHEMA_A"."LKU_CODE"
      on (
        "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."ASSOCIATION_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
        and "SCHEMA_A"."LKU_CODE"."CODE" = 'RESPONSIBLE_MISSION_DIRECTORATE'
      )
      join "SCHEMA_A"."LKU_CODE_TYPE"
      on (
        "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
        and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'PORTFOLIO_ORGANIZATION_ASSOCIATION_TYPE'
      )
  )
  on "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID" = "SCHEMA_A"."LIBRARY"."LIBRARY_ID"
  left outer join (
    "SCHEMA_A"."LIBRARY_ORGANIZATIONS"
      join (
        "SCHEMA_A"."ORGANIZATIONS" "LeadCenter"
          left outer join "SCHEMA_A"."ORGANIZATIONS" "AuxLeadCenter"
          on (
            "LeadCenter"."REPLACEMENT_ORGANIZATION_ID" = "AuxLeadCenter"."ORGANIZATION_ID"
            and "LeadCenter"."IS_ACTIVE" = 0
          )
      )
      on "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."ORGANIZATION_ID" = "LeadCenter"."ORGANIZATION_ID"
      join "SCHEMA_A"."LKU_CODE"
      on (
        "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."ASSOCIATION_TYPE_ID" = "SCHEMA_A"."LKU_CODE"."LKU_CODE_ID"
        and "SCHEMA_A"."LKU_CODE"."CODE" = 'LEAD_CENTER'
      )
      join "SCHEMA_A"."LKU_CODE_TYPE"
      on (
        "SCHEMA_A"."LKU_CODE"."LKU_CODE_TYPE_ID" = "SCHEMA_A"."LKU_CODE_TYPE"."LKU_CODE_TYPE_ID"
        and "SCHEMA_A"."LKU_CODE_TYPE"."CODE_TYPE" = 'PORTFOLIO_ORGANIZATION_ASSOCIATION_TYPE'
      )
  )
  on "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID" = "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID"
order by case when "SCHEMA_A"."LIBRARY_ITEMS"."UPDATE_DATE" is null then "SCHEMA_A"."LIBRARY_ITEMS"."CREATE_DATE"
              else "SCHEMA_A"."LIBRARY_ITEMS"."UPDATE_DATE"
         end desc

我发现的解决方法是删除对 Keys.PO_P___FK 的第二个引用并将其替换为实际密钥,但是其他人看到了吗?有谁知道为什么它第一次正确地将数据设置为"SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID" = "SCHEMA_A"."LIBRARY"."LIBRARY_ID",但第二次它会导致交叉连接,因为它将打开设置为"SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID" = "SCHEMA_A"."LIBRARY_ORGANIZATIONS"."LIBRARY_ID"

【问题讨论】:

  • 这里的问题很可能是在调用第二个onKey()方法的阶段,连接表树中的LIBRARY_ID列不明确。您在日志中看到任何警告吗?从 jOOQ 3.7.3 开始应该有一个警告,当进行模棱两可的查找时 (github.com/jOOQ/jOOQ/issues/5047)
  • 我看到了你所说的警告,当我加入一个有子连接的东西时,我只是打一个空的onKey() 电话,但当我打一个onKey(ForeignKey&lt;?, ?&gt; key) 电话时却没有。我实际上已经在 jOOq 中针对别名表进行了onKey(ForeignKey&lt;?, ?&gt; key) 调用(愚蠢地,我可能会添加),这当然是 jOOq 允许的,但这引发了一个 SQL 异常,因为(显然)jOOq 放入了 ForeignKey,只是正如我所问但没有使用别名。出于好奇,有没有一种好方法可以将 FK 从别名表中提取出来?
  • 有一个应该修复的问题:github.com/jOOQ/jOOQ/issues/2870。如果问题仍然存在,或者修复未完成,可能值得单独提出一个问题?
  • 嗯...问题是我正在针对别名执行onKey(Keys.&lt;FK_NAME&gt;),并且因为有些针对连接多个表的内部连接,所以我不能使用onKey(),因为它告诉我它不明确.也许我会稍微研究一下并单独发布,但我认为这两件事略有不同,因为一个是 onKey() 确定要使用的密钥,另一个是我指定 Keys 条目。

标签: java sql jooq


【解决方案1】:

ON KEY 连接方法通过查找两边的“最佳”匹配表转换为普通的ON 连接谓词。有一个错误 (#5209),通过该错误 first 匹配键中的外键表,并且在匹配时不验证主键表。正因为如此,关键是在错误的方向解决。

在您的查询中,"SCHEMA_A"."LIBRARY_ORGANIZATIONS" 表在没有重命名的情况下连接了两次:

left outer join (
    "SCHEMA_A"."LIBRARY_ORGANIZATIONS"
      join "SCHEMA_A"."ORGANIZATIONS" "RespMissionDir"

还有:

  left outer join (
    "SCHEMA_A"."LIBRARY_ORGANIZATIONS"
      join (
        "SCHEMA_A"."ORGANIZATIONS" "LeadCenter"

jOOQ 无法正确解决这种歧义。从 jOOQ 3.7.3 (#5047) 开始,您应该会在日志文件中看到一条警告,表明您对 onKey() 的使用无法明确解决。

一般来说,当连接表树变得过于复杂时,最好避免使用onKey()

【讨论】:

  • 爆炸吧(关于你的最后一句话)!你知道我有多喜欢onKey(Keys.XXX) 的电话吗?实际上,我真的很想能够注入多个 FK(对于那些很少有用的时候)。我喜欢我可以只做onKey(Keys.%ChildTableAcr%_%ParentTableAcr%___FK) 而不必担心 FK 真正说的是什么(所以如果它改变了,我只需重建我的 jOOq 代码,生活就会很好)。至于身体,真的是暧昧吗?我用Keys 条目调用onKey。我很确定我可以使用其他两个表的 Keys 条目进行这样的调用,并且 jOOq 会将其放入。
  • 我同意使用onKey() 很好,但也很危险,因为它不明确。随着查询的增长,语义可能会变得模棱两可,而最初并非如此。不过,我怀疑在这种情况下您是对的,并且存在错误。之所以会出现歧义,是因为仅根据外键表(不明确)检测键的方向,而不是基于主键表(非歧义)。我为此创建了一个问题:github.com/jOOQ/jOOQ/issues/5209。感谢您的报告!
  • 很高兴您找到了一种简单的复制方法!我担心这可能是那些复杂的事情之一。感谢您开票和解释/讨论!
  • @DanO:我也害怕这个,但幸运的是,这是一个“简单”的问题:)
猜你喜欢
  • 1970-01-01
  • 2020-01-03
  • 1970-01-01
  • 2015-07-13
  • 2015-09-13
  • 2021-12-13
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
相关资源
最近更新 更多