Oracle Insert with nodeJS causing missing keyword error - node.js

I am trying to create table and insert data into oracle db using nodeJS
below is my query code
oracledb.getConnection(
{
user: userId,
password: password,
connectString: `(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = ${host})(PORT = ${port}))(CONNECT_DATA = (SID = ${sid})))`
},
function (err, connection) {
if (err) {
errorHandler(err);
return;
}
connection.execute(
query,
function (err, result) {
if (err) {
errorHandler(err);
oracleFunctions.connection.doRelease(connection, errorHandler);
return;
}
successHandler(result);
oracleFunctions.connection.doRelease(connection, errorHandler);
});
});
As a query I am using the below for creating table.
begin
execute immediate 'CREATE TABLE "table0" ("Channel" VARCHAR(128),
"Pay_mode" VARCHAR(128),
"Product_group" VARCHAR(128),
"PivotDimension" VARCHAR(128),
"Values" DECIMAL(18,6))';
execute immediate 'CREATE TABLE "table1" ("Channel" VARCHAR(128),
"Pay_mode" VARCHAR(128),
"Product_group" VARCHAR(128),
"PivotDimension" VARCHAR(128),
"Values" DECIMAL(18,6))';
end;
I am also using the below for inserting data into the created tables.
INSERT ALL
INTO "table0" VALUES ('AM' , 'PP' , 'NP ISP Annuity' , '1' , '0.11' )
INTO "table0" VALUES ('AM' , 'PP' , 'NP ISP Annuity' , '2' , '0.26' )
SELECT * from dual;
These queries work perfectly on Jetbrain's DataGrip.
I am executing the create table query first and when success response is returned, I am inserting rows into the tables.
However, strangely, when I execute the code, two errors occur
Error: ORA-00955: name is already used by an existing object
ORA-06512: at line 2
for creating table and
Error: ORA-00905: missing keyword
for inserting into the table.
Even more strangely, the table gets created fine but the insertion does not happen.
I have checked many times to make sure that the create table runs only once and insertion only runs once for each table. What could I possibly be doing wrong?

There is nothing strange here. You're asked to do doubtful things and Oracle tries to complete it, no more.
First of all, when using Oracle, you should almost never to create tables dinamically. ORA-955 means that you executed your request more than once. You created tables, ok. You asked to create it again. What answer you're waiting for? Oracle said that these tables already exists. Nothing strange, I guess.
ORA-905, most probably, means that you tries to execute select * from dual as a part of INSERT ALL statement. Oracle is waiting for next INTO statement but got SELECT instead of it, so it indicates syntax error. Again, nothing strange.

Related

SQL Procedure with NodeJs

I am new to SQL. I need to create a procedure that returns a number of orders for each customer.
I have a 'customers' table and an 'orders' table. Both tables are in the same database "shop".
In the end I need to get an array of all customers and the number of orders was placed.
this is what I have, somthing I'm doing wrong, i have an error with wrong syntax
CREATE PRODIDURE customers.total_count(IN id INT)
BEGIN
SELECT COUNT
FROM orders AS order_count INNER JOIN as order_count
ON customers.id= orders.id
WHERE contacts.id = id
END
another question - can I call for the procedure within NodeJS?
pls advice the correct syntax for it
export function getCustomers(){
const [result] = await shop.execute( ??????? )
return result
}
pls help
To call SQL procedures from within NodeJS, you need to use an sql library. In this example from some of my own projects, I am using the MySQL library and connection pools.
const query = "CALL StoredProcedureName(?, ?);"
sql.query(query, [variable1, variable2], function(result, error) {
if (error) {
//do something with the error
return;
}
//do something here with result
})
The example I've given above avoids sql injection by replacing the question marks with the variables inside the brackets.

Sequelize - Update table that has trigger on it - not working

I am kinda of new with Sequelize and Node.js
I am trying to use Sequelize with a MSSQL database and figure out what i can do with it.
I've established the connection, created a model based on a existing table.
Such table has multiple triggers on it.
When i try to execute something like this
sampletable.update({
NAME: "TEST"
},
{
where: {ID: 0},
silent: true
},
).then(function(result){
console.log(result);
})
where "sampletable" is an imported model
var sampletable = sequelize.import('./models/sampletable.js');
that was created with with "SequelizeAuto" (based on existing table's structure)
var SequelizeAuto = require('sequelize-auto')
var auto = new SequelizeAuto(config.database, config.username, config.password, config);
auto.run(function (err) {
if (err) throw err;
});
i get following error
"Unhandled rejection SequelizeDatabaseError: The target table 'sampletable' of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause."
Statement executed
Executing (default): UPDATE [sampletable] SET [NAME]=N'test' OUTPUT INSERTED.* WHERE [id] = 0
Is it possible to update table with triggers with sequelize??
If yes, can anybody point me in the right direction??
I've googled, checked doco, but i can;t find much about it.
TIA
Try adding hasTrigger: true to your model options. This prevents Tedious from trying to output the results from the base table, and uses a temp table instead.

Query condition missed key schema element : Validation Error

I am trying to query dynamodb using the following code:
const AWS = require('aws-sdk');
let dynamo = new AWS.DynamoDB.DocumentClient({
service: new AWS.DynamoDB(
{
apiVersion: "2012-08-10",
region: "us-east-1"
}),
convertEmptyValues: true
});
dynamo.query({
TableName: "Jobs",
KeyConditionExpression: 'sstatus = :st',
ExpressionAttributeValues: {
':st': 'processing'
}
}, (err, resp) => {
console.log(err, resp);
});
When I run this, I get an error saying:
ValidationException: Query condition missed key schema element: id
I do not understand this. I have defined id as the partition key for the jobs table and need to find all the jobs that are in processing status.
You're trying to run a query using a condition that does not include the primary key. This is how queries work in DynamoDB. You would need to do a scan for the info in your case, however, I don't think that is the best option.
I think you want to set up a global secondary index and use that to query for the processing status.
In another answer #smcstewart responded to this question. But he provides a link instead of commenting why this error occurs. I want to add a brief comment hoping it will save your time.
AWS docs on Querying a Table states that you can do WHERE condition queries (e.g. SQL query SELECT * FROM Music WHERE Artist='No One You Know') in the DynamoDB way, but with one important caveat:
You MUST specify an EQUALITY condition for the PARTITION key, and you can optionally provide another condition for the SORT key.
Meaning you can only use key attributes with Query. Doing it in any other way would mean that DynamoDB would run a full scan for you which is NOT efficient - less efficient than using Global secondary indexes.
So if you need to query on non-key attributes using Query is usually NOT an option - best option is using Global Secondary Indexes as suggested by #smcstewart.
I found this guide to be useful to create a Global secondary index manually.
If you need to add it using CloudFormation here is a relevant page.
I was getting this error for a different scenario. Here is my scenario.
(It's very unlikely that anyone else ends up with this case, but incase)
I had a query working on a Table (say table A). Table A had a partition key m_id and sort key u_id.
I had a query to fetch data using m_id. The query was working.
'''
var queryParams = {
ExpressionAttributeValues: {
':m_id': mId
},
KeyConditionExpression: 'm_id = :m_id',
TableName: "A"
};
let connections = await docClient.query(queryParams).promise();
'''
I created another Table say Table B. I made some errors in naming keys so I simply deleted and created a table with the same name again, Table B. Table B had partition key m_id, and sort key s_id.
I copied pasted the same query which I was using for Table A, I changed Table name only because partition key had the same name.
To my shock, I get this expectation.
"ValidationException: Query condition missed key schema element"
I rechecked all the names, I compared the query with the working query. Everything was fine.
I thought maybe because, I was deleting recreating Table B, it could be something with that. So I create a fresh Table with a new Name Table B2 with the same key names as Table B.
In my query that was throwing exceptions, I changed only the Table name from B to B2.
And the Exception was gone.
If you are getting this on a fresh table, where no query has worked earlier, creating a new Table with a new name is an option.
If you delete a Table only to change partition key names, it may be safer to use a new name for Table as well (Dynamo could be referring metadata by table names and not by internal identifiers, it is possible that old metadata stays even if you delete a table. Just a guess given I faced this case).
EDIT:2022-July-12
This error does not leave me. My own answer was helpful but one more case, there was a trailing space in name of Key in the table. And Dynamo does not even check for spaces in key names.
You have to create an global secondary index for the status field.
Then, you code could look like smth like this:
dynamo.query({
TableName: "Jobs",
IndexName: 'status',
KeyConditionExpression: '#s = :st',
ExpressionAttributeValues: {
':st': 'processing'
},
ExpressionAttributeNames: {
'#s': 'status',
},
}, (err, resp) => {
console.log(err, resp);
});
Note: scan operation is indeed very costly, especially if you table is huge in size
i solved the problem using AWS.DynamoDB.DocumentClient() with scan, for sample (nodejs):
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "product",
FilterExpression: "#cg = :data",
ExpressionAttributeNames: {
"#cg": "categoria",
},
ExpressionAttributeValues: {
":data": category,
}
};
docClient.scan(params, onScan);
function onScan(err, data) {
if (err) {
// for the log in server
console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2));
res.json(err);
} else {
console.log("Scan succeeded.");
res.json(data);
}
}

Node.js Firebird SQL connector - getting result from INSERT ... RETURNING

I am trying to write a function that lets me insert a value into the firebird database. The query works well, only I get no callback to tell me that the insert went well.
It is the first time I am using a firebird connector. In the past, when using mySql connectors I can recall having some sort of callback when inserting new values. Right now I am using the node-firebird library by Henri Gourvest to accomplish this:
https://github.com/hgourvest/node-firebird/
I tried adding 'RETURNING FEATURE_ID' at the end, but an error "Cursor is not open" was thrown. The feature ID is generated by a trigger.
Any advice would be very kind.
pool.get(function(error, db) {
if (error) {
console.log(error)
res.status(403)
res.send()
}
else {
var date = moment(req.body.date, "DD/MM/YYYY")
var values = " VALUES ('" + date.format("MM/DD/YYYY") + "','Requested','" + req.body.type + "','" + req.body.description + "','" + req.body.memo +"')"
var query = 'INSERT INTO "Features" (FEATURE_REQUESTDATE, FEATURE_STATUS, FEATURE_TYPE, FEATURE_DESCRIPTION, FEATURE_MEMO)' + values
db.query( query , function(err, result) {
if (result) { //why is there no result here?
res.status(200)
res.send('ok')
}
if (err) {
console.log(err)
res.status(403)
res.send('error')
}
})
db.detach();
}
})
I tried adding 'RETURNING FEATURE_ID' at the end, but an error "Cursor is not open" was thrown.
Sure, there can be no cursor. Cursors (AKA rowsets) are only created by queries - SELECT-type SQL statements.
As stated in Firebird documentation, statements with RETURNING clause are not of query type, they are of procedure call type. You should execute them as you do with regular DELETE-type statements, then read the PARAMETERS of the statement executed.
Right now I am using the node-firebird library by Henri Gourvest to accomplish this: https://github.com/hgourvest/node-firebird/
Any advice would be very kind.
There are two advices.
NEVER do splice your data values into SQL command text. It makes your program very fragile. It would give you all the kinds of data conversion errors, and also it opens highways for your database corruption made by unexpected - erroneous or malicious - user input. See http://bobby-tables.com/ and http://en.wikipedia.org/wiki/SQL_injection
"Use the source Luke". The library you mentioned is open-source. So you have to check the examples in that library. Henri is known to be very laconic about documentation. However he supplies his different libraries with vast sets of examples and/or tests. Both suit for you, as they do use the library, and so you can just read how the library was intended to be used by its creator. This particular library has tests. And tests are always examples of intended use.
So you go into test folder and you see there run.js file. Open it.
https://github.com/hgourvest/node-firebird/blob/master/test/run.js
Now press Ctrl+F and search for "RETURNING" word. Not always first time, but one of its occurrences should be exactly test for the SQL feature you need.
Here it is, the very FIRST occurrence of it in the library text you already have on your machine. Granted, the first occurrence adds complexity of working with BLOBs that you do not need right off. So I would quote the THIRD example in the library you downloaded. But even the first example shows you how to properly execute queries with values and with RETURNING clauses.
function test_insert(next) {
....skip.......
// Insert record without blob
database.query('INSERT INTO test (ID, NAME, CREATED, PARENT) VALUES(?, ?, ?, ?) RETURNING ID', [3, 'Firebird 3', now, 862304020112911], function(err, r) {
assert.ok(!err, name + ': insert without blob (buffer) (1) ' + err);
assert.ok(r['id'] === 3, name + ': without blob (buffer) returning value');
next();
});
// Insert record without blob (without returning value)
database.query('INSERT INTO test (ID, NAME, CREATED) VALUES(?, ?, ?)', [4, 'Firebird 4', '2014-12-12 13:59'], function(err, r) {
assert.ok(!err, name + ': insert without blob (buffer) (2) ' + err);
assert.ok(err === undefined, name + ': insert without blob + without returning value');
next();
});

pg-promise doesn't delete but doesn't throw error either

I have the following query which successfully delete records when I run it in the psql shell:
delete from schedule_set USING schedule, event WHERE (schedule.schedule_set_id = schedule_set.id) and (schedule_set.id = ${id}) and (select count(*) from event where (complete IS TRUE)) = 0 RETURNING *
I'm generating the query with a JS function - that's why I have ${id} in the query, than call the following:
return db.any(schedule.deleteSchedulesByScheduleSetId(params), params)
.catch(err => {
console.log(err);
});
When I have a syntax error in the query I get an error - this tells me that the query is being ran against the database. When I fix the syntax I don't get any errors but nothing is deleted either.
Any ideas why or how to debug? - thanks
Method any, as documented, only rejects when executing the query results in an error. If your DELETE query doesn't delete anything, it is not an error.
If you want your DELETE query to result in an error when it doesn't delete anything, you can use RETURNING * in the end of the query, and execute it either with many or one, depending on how many records it is expected to delete (and thus return) normally.
The most practical approach however is not to use any of the above, because returning deleted rows is an extra operation, typically useless. Instead, you should rely on the number of rows actually deleted, and then act accordingly.
For that you would you use method result, converting the output into the number of rows affected (deleted in your case):
db.result(query, values, a => a.rowCount)
.then(count => {
// count = number of rows deleted
})
.catch(error => {
// error
})

Resources