Вставьте несколько записей в SQL Server с помощью Node.js

Я переписываю старый 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);
});

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

Request.multiple = true

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

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

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

RequestError: Incorrect syntax near '?'.

Вот и все.

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

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

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

0
as 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.

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

Резюме

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

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

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

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

James 10.12.2018 23:30

@ Джеймс от 1 до ~ несколько сотен

marrem97 11.12.2018 09:26

@ marrem97 Удалось ли вам найти решение этого вопроса? У меня точно такая же проблема. Спасибо

newbie 24.01.2021 21:49

@newbie, к сожалению, нет. В конечном итоге я использовал то, что я назвал «ленивым способом», с Promise.all для всех приведенных записей. Однако я долго не работал над этим проектом, так что я особо не занимался исследованиями.

marrem97 26.01.2021 14:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
4
1 840
0

Другие вопросы по теме