2016-04-15 5 views
0

У меня, похоже, есть ошибка в jOOq 3.7.3, если мы ссылаемся на константу Keys дважды. Возьмем следующий пример:jOOq Key вызывает плохой запрос

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 12С):

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"?

+0

Проблема в том, что столбец 'LIBRARY_ID' является неоднозначным в дереве таблиц соединений на этапе, когда вызывается второй метод' onKey() '. Вы видите предупреждение в журналах? Должно быть предупреждение с jOOQ 3.7.3, когда сделаны неоднозначные поисковые запросы (https://github.com/jOOQ/jOOQ/issues/5047) –

+0

Я видел предупреждения, о которых вы говорите, когда я просто делаю empty 'onKey()' call, если я присоединяюсь к тому, что имеет subjoins, но не когда я делаю 'onKey (ForeignKey ключ)' call. Я действительно сделал ключ 'onKey (ForeignKey )' в jOOq (тупо, я мог бы добавить) против aliased-таблицы, которую, конечно, разрешил jOOq, но это вызвало исключение SQL, потому что (очевидно) jOOq put в ForeignKey, как я и спросил, но не использовал псевдоним. Из любопытства, есть ли хороший способ вытащить FK из таблицы с псевдонимом? – DanO

+0

Была проблема, которая должна была быть исправлена: https://github.com/jOOQ/jOOQ/issues/2870. Может быть стоит отдельный вопрос, если проблема все еще сохраняется или если исправление не было полным? –

ответ

1

Метод соединения ON KEY переводится в обычный предикат соединения ON путем нахождения «лучших» совпадающих таблиц с обеих сторон. Существует ошибка (#5209), по которой таблица внешнего ключа в ключе сопоставляется с первым, а после соответствия таблица первичных ключей не проверяется. Из-за этого ключ разрешается в неправильном направлении.

В запросе, таблица "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(), когда деревья таблицы соединений становятся слишком сложными.

+0

Взрыв (относительно вашего последнего предложения)! Знаете ли вы, насколько я обожаю 'onKey (Keys.XXX)' звонки? На самом деле, мне очень хотелось бы прокачивать несколько FK (для тех редких случаев, когда это полезно). Мне нравится, что я могу просто делать onKey (Keys.% ChildTableAcr% _% ParentTableAcr% ___ FK) 'и не беспокоиться о том, что действительно говорит FK (поэтому, если он изменится, я просто перестрою свой код jOOq, и жизнь хороша) , Что касается тела, это действительно двусмысленно? Я вызываю 'onKey' с записью' Keys'.Я уверен, что я мог бы сделать такой вызов с помощью записи Keys для двух других таблиц, и jOOq поместит его. – DanO

+0

Я согласен, что использование 'onKey()' приятно, но оно также предательски, потому что оно не является явным , По мере роста запроса семантика может стать неоднозначной, когда она была не первой. Я подозреваю, что вы правы в этом случае, и есть ошибка. Неоднозначность возникает только потому, что направление ключа обнаруживается только на основе таблицы внешнего ключа (неоднозначно), а также не основано на таблице первичных ключей (не двусмысленной). Я создал проблему для этого: https://github.com/jOOQ/jOOQ/issues/5209. Спасибо за сообщение! –

+0

Я рад, что вы нашли простой способ воспроизведения! Я боялся, что это может быть одна из тех сложных вещей. Спасибо, что открыли билет и объяснили/обсудили! – DanO