Могу ли я использовать MERGE INTO для имитации upsert в Apache Derby?

Мы используем Derby, и у нас много кода, который выглядит примерно так:

try (ResultSet rs = executeQuery(...)) {
    if (rs.next()) {
        updateRowSet(rs, ...);
        rs.updateRow();
    } else {
        executeUpdate(...);
    }
}

Раньше мы искали способ реализовать эту логику на стороне сервера и обнаружили, что некоторые базы данных поддерживают операцию «upsert» (обновление или вставка). У Дерби был запрос функции для MERGE INTO, который предположительно был стандартным способом выполнения этого в SQL: 2003, поэтому мы сидели и смотрели заявку, и прошло много времени.

Наконец, Derby 10.11 добавил MERGE INTO. Никто еще не успел просмотреть и обновить код, чтобы использовать его, но при чтении их документации все их примеры показывают слияние одной таблицы с другой. Но подождите, наших данных еще нет в таблице!

Я знаю, что могу поместить его в таблицу, но тогда это снова несколько запросов, что полностью лишает смысла его использование.

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

Вот что я пробовал:

try (PreparedStatement ps = connection.prepareStatement(
        "MERGE INTO things AS target " +
        // Awkward point 1:
        // It wants a "source" table, but I don't have one.
        // So I thought I would try to use the same table with
        // another name.
        "  USING things AS source ON target.id = ?" +
        "  WHEN MATCHED THEN" +
        "    UPDATE SET data = ?" +
        "  WHEN NOT MATCHED THEN" +
        "    INSERT (id, data) VALUES (??, ?)"))
{
    ps.setLong(1, id);
    ps.setBinaryStream(2, data);
    ps.setLong(3, id);
    // Awkward point 2:
    // Passing an InputStream into a query as two
    // parameters.
    ps.setBinaryStream(4, data);
    ps.execute();
}

Похоже, что это не делает никаких вставок, но также не дает ошибок, так что мне абсолютно нечего делать.


person Trejkaz    schedule 12.01.2016    source источник
comment
Возможно полезные связанные вопросы: stackoverflow.com/questions/11216067/ и stackoverflow.com/questions/2479488/   -  person Bryan Pendleton    schedule 12.01.2016
comment
Я не думаю, что это возможно с Дерби. Он не допускает постоянных значений в качестве источника оператора слияния.   -  person a_horse_with_no_name    schedule 12.01.2016


Ответы (2)


Разделяю его со всеми грустными людьми, которые все еще используют дерби :) Итак, я решил это с помощью merge into statement (https://db.apache.org/derby/docs/10.14/ref/rrefsqljmerge.html) таким образом:

MERGE INTO foo
USING SYSIBM.SYSDUMMY1
ON foo.id = '1' AND foo.language = 'en'
WHEN MATCHED THEN
  UPDATE SET name = 'name2', image = 'someImgUrl2'
WHEN NOT MATCHED THEN
  INSERT (id, name, language, image)
  VALUES ('1', 'name1', 'en', 'someImgUrl1')

Где foo - это таблица, в которой вы хотите вставить строку и SYSIBM.SYSDUMMY1 фиктивную таблицу дерби, которая имеет только одну бесполезную строку (кстати, она не работает с одной из моих обычных таблиц, в которой есть несколько строк)

Как вы понимаете, это больше похоже на обходной путь, но лучше, чем ничего для достижения цели.

person Dzmitry Hubin    schedule 18.07.2018
comment
имея CREATE TABLE foo(id VARCHAR(2), name VARCHAR(48), language VARCHAR(48), image VARCHAR(48)) и используя это, я получаю java.sql.SQLSyntaxErrorException: столбец 'FOO.ID' либо отсутствует в какой-либо таблице в списке FROM, либо отображается в спецификации соединения и выходит за рамки спецификации соединения или появляется в предложении HAVING и не входит в список GROUP BY. Если это оператор CREATE или ALTER TABLE, то «FOO.ID» не является столбцом в целевой таблице. Использование derby 10.14.2.0. - person eis; 17.08.2018
comment
ах, нашел проблему! У вас есть цель foo AS, но вы все еще используете в ней 'foo'. Исправление и голосование. - person eis; 17.08.2018
comment
Кроме того, кажется, что при использовании этого значения столбца по умолчанию не соблюдаются в части вставки, как в обычных операторах вставки. Похоже, это ошибка в Дерби. - person eis; 17.08.2018

С Apache Derby 10.12.1.1 у меня работало следующее:

merge into FOO
using RANDOM_TABLE
on FOO.guid = 'qwerty'
when matched then
    update set guid = 'qwerty'
when not matched then
    insert (guid) values('qwerty')       

Здесь FOO - моя целевая таблица для выполнения обновления, а RANDOM_TABLE - любая другая таблица в моей базе данных. Значение qwerty - это мои данные и уникальный ключ. В этом примере FOO имеет только один столбец, но он должен работать, чтобы просто добавить дополнительные столбцы для вставки и обновления соответственно.

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

person Simon S    schedule 13.03.2016
comment
Странно, у меня просто Error code 30000, SQL state 42X01: Syntax error: Encountered "INTO" at line 7, column 12. - person Hooli; 29.07.2016