仅在循环中多次插入最后一个值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仅在循环中多次插入最后一个值相关的知识,希望对你有一定的参考价值。
我正在读取XLSX文件,并将记录插入ORACLE数据库。 XLSX包含以下值
H
H
H
H
JK
但是只有JK插入了5次。下面是使用的代码
var XLSX = require('xlsx')
var workbook = XLSX.readFile('Accounts.xlsx');
var sheet_name_list = workbook.SheetNames;
var xlData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
var connection;
var oracledb = require('oracledb');
oracledb.autoCommit = true;
var dbConfig = require(__dirname + '/dbconfig.js');
var cnt;
oracledb.getConnection(
dbConfig,
function(err, connection) {
if (err) throw err;
for (i in xlData)
{
var act_fam = xlData[i].ACCOUNT_FAMILY;
connection.execute(
`SELECT * FROM TFAMCORGDS_TEST WHERE MNEFAMCOR='`+ act_fam + `'`,
function(err, results) {
if (err) throw err;
cnt = results.rows.length;
if (cnt === 0)
{
connection.execute(
`INSERT INTO TFAMCORGDS_TEST (CODFAMCOR,MNEFAMCOR,DATMOD,DATFINACT) VALUES (SCORGDS.NEXTVAL,'`+ act_fam + `',SYSDATE,NULL)`,
function(err, results) {
if (err) throw err;
console.log('Rows Inserted: ', results.rowsAffected);
//do work on the rows here
}
);
}
});
}
}
);
而且我也不能在"cnt"
函数之外使用变量connection.execute
值,尽管它是全局变量。
我将任务划分为不同的功能,并将它们包装在promise中,而不是在循环中放置回调。代码看起来像这样
var XLSX = require("xlsx");
var workbook = XLSX.readFile("Accounts.xlsx");
var sheet_name_list = workbook.SheetNames;
var xlData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
var connection;
var oracledb = require("oracledb");
oracledb.autoCommit = true;
var dbConfig = require(__dirname + "/dbconfig.js");
var cnt;
function getConnection() {
return new Promise((resolve, reject) => {
oracledb.getConnection(dbConfig, function(err, connection) {
if (err) {
reject(err);
}
resolve(connection);
});
});
}
function get(connection, act_fam) {
return new Promise((resolve, reject) => {
connection.execute(`SELECT * FROM TFAMCORGDS_TEST WHERE MNEFAMCOR='` + act_fam + `'`, function(err, results) {
if (err) {
reject(err);
}
resolve(results);
});
});
}
function insert(connection, act_fam) {
return new Promise((resolve, reject) => {
connection.execute(
`INSERT INTO TFAMCORGDS_TEST (CODFAMCOR,MNEFAMCOR,DATMOD,DATFINACT) VALUES (SCORGDS.NEXTVAL,'` +
act_fam +
`',SYSDATE,NULL)`, function(err, results) {
if (err) {
reject(err);
}
resolve(results);
});
});
}
async function main() {
const connection = await getConnection();
for (i in xlData)
{
var act_fam = xlData[i].ACCOUNT_FAMILY;
const results = await get(connection, act_fam);
cnt = results.rows.length;
if (cnt === 0) {
const insertResult = await insert(connection, act_fam);
console.log('Rows Inserted: ', insertResult.rowsAffected);
}
}
}
希望这会有所帮助
您应该创建一个单独的异步函数来访问数据库。因为当我们执行一些数据库操作时需要花费一些时间。我们必须等到完成后再处理下一个。因此,我不会将整个代码放在这里。只是一个例子。
async function main(){
//send the data to database accessing function
for(i in xlData){
await insertData(xlData[i].ACCOUNT_FAMILY);
}
}
async function insertData(data){
//do the database stuff here
}
NOTE:我正在使用await
关键字执行异步功能。
[我喜欢Ashish Modi的答案,但是我不认为他知道驱动程序已经支持promises,因此可以简化他的代码。
首先,您不需要getConnection
函数。如果您不传递回调,则驱动程序的getConnection
函数已经返回了promise,因此该函数不会添加任何内容。
get
功能有相同的问题。不需要,因为驱动程序的execute
方法已经支持promises。
代码可能看起来像这样:
var XLSX = require("xlsx");
var workbook = XLSX.readFile("Accounts.xlsx");
var sheet_name_list = workbook.SheetNames;
var xlData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
var connection;
var oracledb = require("oracledb");
oracledb.autoCommit = true;
var dbConfig = require(__dirname + "/dbconfig.js");
async function main() {
const connection = await oracledb.getConnection(dbConfig);
for (i in xlData)
{
var act_fam = xlData[i].ACCOUNT_FAMILY;
const results = await connection.execute(`SELECT * FROM TFAMCORGDS_TEST WHERE MNEFAMCOR='` + act_fam + `'`);
var cnt = results.rows.length;
if (cnt === 0) {
const insertResult = await connection.execute(
`INSERT INTO TFAMCORGDS_TEST (CODFAMCOR,MNEFAMCOR,DATMOD,DATFINACT) VALUES (SCORGDS.NEXTVAL,'` +
act_fam +
`',SYSDATE,NULL)`);
console.log('Rows Inserted: ', insertResult.rowsAffected);
}
}
}
但是,代码仍然存在很大的问题:SQL注入漏洞和过多的往返行程。
该代码当前正在使用字符串串联将值传递给SQL语句,这将使您面临SQL注入和性能问题。您应该改为使用绑定变量,如此处所述:https://oracle.github.io/node-oracledb/doc/api.html#bind
代码如下所示:
var XLSX = require("xlsx");
var workbook = XLSX.readFile("Accounts.xlsx");
var sheet_name_list = workbook.SheetNames;
var xlData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
var connection;
var oracledb = require("oracledb");
oracledb.autoCommit = true;
var dbConfig = require(__dirname + "/dbconfig.js");
async function main() {
const connection = await oracledb.getConnection(dbConfig);
for (i in xlData)
{
var act_fam = xlData[i].ACCOUNT_FAMILY;
const results = await connection.execute('SELECT * FROM TFAMCORGDS_TEST WHERE MNEFAMCOR= :act_fam', [act_fam]);
var cnt = results.rows.length;
if (cnt === 0) {
const insertResult = await connection.execute(
'INSERT INTO TFAMCORGDS_TEST (CODFAMCOR,MNEFAMCOR,DATMOD,DATFINACT) VALUES (SCORGDS.NEXTVAL, :act_fam,SYSDATE,NULL)', [act_fam]);
console.log('Rows Inserted: ', insertResult.rowsAffected);
}
}
}
现在该代码既简单又安全。如果您只处理几行(并且该行数不会随着时间增加),则可以停在那里,并且性能还可以。否则,请继续...
当前实现正在执行我们所谓的逐行或逐个慢速处理。作为开发人员,您应该尝试避免过多的网络往返(网络是最糟糕的I / O类型)。您在循环中有两个execute
调用,因此循环的每次迭代都是两次往返。
使用Oracle,您可以使用许多工具来减少往返行程,因此您可以在此处采用不同的方法。例如,您可以查看executeMany
:https://oracle.github.io/node-oracledb/doc/api.html#-30-database-round-trips
但是,在这种情况下,我认为最简单的方法可能是将语句作为匿名PL / SQL块发送到数据库。看起来像这样:
var XLSX = require("xlsx"); var workbook = XLSX.readFile("Accounts.xlsx"); var sheet_name_list = workbook.SheetNames; var xlData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]); var connection; var oracledb = require("oracledb"); oracledb.autoCommit = true; var dbConfig = require(__dirname + "/dbconfig.js"); async function main() { const connection = await oracledb.getConnection(dbConfig); const act_fams = []; for (i in xlData) { act_fams.push(xlData[i].ACCOUNT_FAMILY); } await connection.execute( `declare type number_aat is table of number index by pls_integer; l_act_fam_arr number_aat; l_count number; begin l_act_fam_arr := :act_fam_arr; for act_fam in 1 .. l_act_fam_arr.count loop select count(*) into l_count from tfamcorgds_test where mnefamcor=act_fam; if l_count = 0 then insert into tfamcorgds_test ( codfamcor,mnefamcor,datmod,datfinact ) values (scorgds.nextval, act_fam,sysdate,null); end if; end loop; end;`, { act_fam_arr: { type: oracledb.NUMBER, val: act_fams } } ); }
我尚未测试此代码,因此可能存在语法错误。请注意,我传递给
execute
的第一个参数是一个很大的代码字符串,即PL / SQL块。第二个参数是绑定变量,它是一个数字数组(我假设ACCOUNT_FAMILY是一个数字,但是如果需要,您可以轻松地将其更改为字符串)。
代码和值将通过一次网络往返发送到数据库。 PL / SQL代码实现了与javascript相同的逻辑。如果您使用此代码与以前的版本进行测试,您应该会看到明显的性能改进(读取的行越多,改进的效果就越明显)。
如果MNEFAMCOR
是唯一的,例如像:
以上是关于仅在循环中多次插入最后一个值的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中的核心数据:仅在 for 循环中保存最后一个对象
通过 for 循环和 php 数组进行多次插入(通过 jQuery AJAX 接收)