Вставьте несколько записей в SQL Server с Node.js - PullRequest
0 голосов
/ 11 декабря 2018

Я переписываю старый API, для которого пытаюсь одновременно вставить несколько значений в базу данных MSSQL-Server (2008), используя модуль узла mssql .Теперь я способен сделать это каким-то образом , но я хочу следовать этим рекомендациям .Я провел свое исследование и перепробовал много вещей для достижения моей цели.Однако я не смог найти ни одного решения, которое бы работало правильно.

До

Вы можете удивиться:

Ну, вы переписываете этот API, поэтому должен быть способ, которым это было сделано раньше, и это работало?

Конечно, вы правы, он работал раньше, но ... не вКак я чувствую себя комфортно с использованием в переписать.Позвольте мне показать вам, как это было сделано раньше (добавлено немного абстракции, конечно):

const request = new sql.Request(connection);
let query = "INSERT INTO tbl (col1, col2, col3, col4) VALUES ";
for (/*basic for loop w/ counter variable i*/) {
    query += "(1, @col2" + [i] + ", @col3" + [i] + ", (SELECT x FROM y WHERE z = @someParam" + [i] + "))";
    // a check whether to add a comma or not
    request.input("col2" + [i], sql.Int(), values[i]);
    // ...
}
request.query(query, function(err, recordset) {
    // ...
}

Пока это работает, опять же, я не совсем думаю, что это можно назвать чем-то вроде «Лучшая практика» .Также это показывает самую большую проблему: для выбора значения используется подвыбор.

То, что я пробовал до сих пор

Простой способ

Сначала я попробовал, вероятно, самую простую вещь:

// simplified
const sQuery = "INSERT INTO tbl (col1, col2, col3, col4) VALUES (1, @col2, @col3, (SELECT x FROM y WHERE z = @col4));";
oPool.request().then(oRequest => {
    return oRequest
        .input("col2", sql.Int(), aValues.map(oValue => oValue.col2))
        .input("col3", sql.Int(), aValues.map(oValue => oValue.col3))
        .input("col4", sql.Int(), aValues.map(oValue => oValue.col4))
        .query(sQuery);
});

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

Request.multiple = true

... и подумал, что это сработает.Но - удивительно - это не так, все же только первый элемент вставлен.

Использование '?'для параметров

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

RequestError: Неверный синтаксис рядом с '?'.

Так много для этого.

Массовая вставка

Некоторые дальнейшие исследования привели к массовой вставке .Довольно интересная, классная функция и отличное обновление вопроса с решением по ОП!У меня были некоторые трудности с началом работы, но в итоге все выглядело действительно хорошо: было вставлено несколько записей, и значения казались нормальными.

Пока я не добавил подзапрос.Использование его в качестве значения для объявленного столбца не вызвало никакой ошибки, однако при проверке значений таблицы просто отображалось значение

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

Ленивый путь

Я действительно не знаю, что об этом думать:

// simplified
Promise.all(aValues.map(oValue => {
    return oPool.request().then(oRequest => 
        oRequest
            .input("col2", sql.Int, oValue.col2)
            .input("col3", sql.Int, oValue.col3)
            .input("col4", sql.Int, oValue.col4)
            .query(sQuery);
    });
});

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

Lazy+ Транзакция

Поскольку продолжалось, даже если какой-то сбой был основной проблемой последнего метода, я попытался построить транзакцию вокруг него.Все запросы успешны?Хорошо, коммит.Любой запрос имеет ошибку?Ну, просто откат чем.Поэтому я создаю транзакцию, перенес в нее свою конструкцию Promise.all и попробовал снова.И в моем терминале появляется следующая ошибка:

TransactionError: Can't acquire connection for the request. There is another request in progress.

Если вы зашли так далеко, мне не нужно сообщать вам, в чем проблема.

Резюме

То, что я еще не пробовал (и не думаю, что попробую это), - это использование способа транзакции и последовательный вызов операторов.Я не верю, что это будет путь.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...