Я переписываю старый API, для которого пытаюсь вставить сразу несколько значений в базу данных MSSQL-Server (2008), используя модуль узла mssql. Теперь я могу сделать это как-то, но я хочу сделать это после лучшие практики. Я провел свое исследование и попробовал многое, чтобы достичь своей цели. Однако мне не удалось найти ни одного решения, которое бы работало правильно.
Вы можете спросить:
Well, you are rewriting this API, so there must be a way this has been done before and that was working?
Конечно, вы правы, это работало раньше, но ... не в том смысле, в котором мне было бы удобно использовать его при перезаписи. Позвольте мне показать вам, как это было сделано раньше (конечно, добавлена небольшая абстракция):
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);
});
Я бы сказал, это была довольно хорошая догадка, и на самом деле она работала относительно нормально. За исключением той части, которая игнорирует каждый элемент после первого ... что делает это довольно бесполезным. Итак, я попробовал ...
... и я подумал, что это сработает. Но - сюрприз - это не так, по-прежнему вставлен только первый элемент.
На этом этапе я действительно начал поиск решения, поскольку второе было лишь быстрым поиском в документации модулей. Я наткнулся на этот ответ и сразу попробовал. Мой терминал не заставил себя долго ждать,
RequestError: Incorrect syntax near '?'.
Вот и все.
Некоторые дальнейшие исследования привели к массовая вставка. Довольно интересная, классная функция и отличное обновление вопроса с решением ОП! Приступая к работе, у меня были некоторые проблемы, но в итоге все выглядело действительно хорошо: было вставлено несколько записей, и значения казались нормальными.
Пока я не добавил подзапрос. Использование его в качестве значения для объявленного столбца не вызывало никаких ошибок, однако при проверке значений в таблице он просто отображал
0as value for this column. Not a big surprise at all, but everybody can dream, right?
Я действительно не знаю, что об этом думать:
// 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);
});
});
Он выполняет свою работу, но если какой-либо из запросов не удается по какой-либо причине, другие, исправные вставки, все равно будут выполняться, даже если это должно быть возможно нет.
Поскольку главной проблемой последнего метода было продолжение, даже если какой-то сбой, я попытался построить транзакцию вокруг него. Все запросы выполнены успешно? Хорошо, совершай. В любом запросе есть ошибка? Ну просто откат чем. Итак, я создал транзакцию, переместил в нее свою конструкцию Promise.all и попытался снова. В моем терминале выскакивает следующая ошибка:
TransactionError: Can't acquire connection for the request. There is another request in progress.
Если вы зашли так далеко, мне не нужно говорить вам, в чем проблема.
То, что я еще не пробовал (и я не думаю, что попробую это сделать), - это использование способа транзакции и последовательного вызова операторов. Я не верю, что это правильный путь.
И я также не думаю, что следует использовать ленивый способ, поскольку он использует отдельные запросы для каждой вставки записи, когда это можно каким-то образом сделать, используя только один запрос. Просто этот как-то, я не знаю, сейчас не в моей голове. Так что, пожалуйста, если у вас есть что-нибудь, что могло бы мне помочь, скажите мне.
Кроме того, если вы видите что-то еще не так с моим кодом, не стесняйтесь указывать на это. Я не считаю себя новичком, но и не думаю, что обучение когда-нибудь закончится. :)
@ Джеймс от 1 до ~ несколько сотен
@ marrem97 Удалось ли вам найти решение этого вопроса? У меня точно такая же проблема. Спасибо
@newbie, к сожалению, нет. В конечном итоге я использовал то, что я назвал «ленивым способом», с Promise.all для всех приведенных записей. Однако я долго не работал над этим проектом, так что я особо не занимался исследованиями.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Итак, я получаю произвольный запрос, но примерно сколько вставок вы ожидаете выполнить?