2016-04-12 3 views
0

Это запрос, я пытаюсь работать в PostgreSQL:Использование unnest как поле, а не за столом в jOOQ

SELECT * FROM message WHERE id IN (
    SELECT unnest(message_ids) "mid" 
     FROM session_messages WHERE session_id = '?' ORDER BY "mid" ASC 
); 

Однако, я не в состоянии сделать что-то:

create.selectFrom(Tables.MESSAGE).where(Tables.MESSAGE.ID.in(
    create.select(DSL.unnest(..)) 

Поскольку DSL.unnest - Table<?>, что имеет смысл, так как он пытается взять объект List-like (в основном буквальный) и преобразовать его в таблицу.

У меня такое чувство, что мне нужно найти способ обернуть функцию вокруг имени моего поля, но я не знаю, как это сделать.

ПРИМЕЧАНИЕ. Поле message_ids имеет тип bigint[].

EDIT

Итак, это то, как я делаю это сейчас, и это работает точно так же, как и ожидалось, но я не уверен, что это лучший способ сделать это:

Field<Long> unnestMessageIdField = DSL.field(
       "unnest(" + SESSION_MESSAGES.MESSAGE_IDS.getName() + ")", 
       Long.class) 
     .as("mid"); 

Field<Long> messageIdField = DSL.field("mid", Long.class); 

MESSAGE.ID.in(
     ctx.select(messageIdField).from(
      ctx.select(unnestMessageIdField) 
       .from(Tables.CHAT_SESSION_MESSAGES) 
        .where(Tables.CHAT_SESSION_MESSAGES.SESSION_ID.eq(sessionId)) 
      ) 
      .where(condition) 
) 

EDIT2

После прохождения через код на https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/DSL.java я думаю, правильный способ сделать это было бы:

DSL.function("unnest", SQLDataTypes.BIGINT.getArrayType(), SESSION_MESSAGES.MESSAGE_IDS) 

EDIT3

Так как всегда Lukas здесь для моих jOOQ горю, я собираюсь заработать на этом :)

Попытка обобщить эту функцию, в подписи рода

public <T> Field<T> unnest(Field<T[]> arrayField) { 
    return DSL.function("unnest", <??>, arrayField); 
} 

I не знаю, как я могу получить тип данных. Кажется, есть способ получить DataType<T[]> от DataType<T> с помощью DataType::getArrayDataType(), но наоборот невозможно. Существует этот класс, который я нашел ArrayDataType, но он кажется закрытым для пакета, поэтому я не могу его использовать (и даже если бы мог, он не показывал поле elementType).

+0

Какую версию PostgreSQL вы используете? –

+0

В настоящее время используется 9.4 (Кроме того, вы можете увидеть EDIT3, пожалуйста?) –

ответ

2

Старые версии PostgreSQL имели эту напуганную идею о том, что нормально создавать таблицу из предложения SELECT и разворачивать ее во «внешнюю» таблицу, как если бы она была объявлена ​​в предложении FROM. Это очень неявное наследие PostgreSQL, и этот пример - хороший шанс избавиться от него и вместо этого использовать LATERAL. Ваш запрос эквивалентен следующему:

SELECT * 
FROM message 
WHERE id IN (
    SELECT "mid" 
    FROM session_messages 
    CROSS JOIN LATERAL unnest(message_ids) AS t("mid") 
    WHERE session_id = '?' 
); 

Это может быть переведен на jOOQ гораздо легче, как:

DSL.using(configuration) 
    .select() 
    .from(MESSAGE) 
    .where(MESSAGE.ID).in(
     select(field(name("mid"), MESSAGE.ID.getDataType())) 
     .from(SESSION_MESSAGES) 
     .crossJoin(lateral(unnest(SESSION_MESSAGES.MESSAGE_IDS)).as("t", "mid")) 
     .where(SESSION_MESSAGES.SESSION_ID.eq("'?'")) 
    ) 
+0

Помимо того, что ваше решение кажется структурно лучше, есть ли разница в производительности между этими двумя методами? И, как всегда, большое вам спасибо за то, что нашли время. –

+0

Интересно, что ваш подход, похоже, дает более простые планы выполнения. Вы должны будете измерить (или задать другой вопрос!) –