Updating with INSERT INTO on Conflict Error - javascript

TWO QUESTIONS IN ONE:
Number one: This returns Failing row contains for name column and some more columns when trying to do it in SQL. However I know for a fact that the id allready exsist in the table. So how can I prevent it from giving this error?
Number two: The code returns error: syntax error at or near "$1" when ran in node? Is it beacuse values is a string and how can i prevent this?
This gives error error: syntax error at or near "$1". I have a feeling
let values = ("("+req.body.oldid+","+false+"),("+req.body.newid+","+true+")")
console.log(values) // returns (70,false),(4,true)
const results = await db.query("INSERT INTO practiceSite (id,frontpage) VALUES $1 ON CONFLICT DO UPDATE frontpage = values(frontpage);",[values])

Based on your use case, it looks like you'll only ever be inserting 2 entries at a time, so this should work.
In your example values is seen as a string, so we need to be more granular and pass in each parameter, and create the rows.
const results = await db.query(`
INSERT INTO practiceSite (id, frontpage)
VALUES ($1, FALSE), ($2, TRUE)
ON CONFLICT
DO UPDATE SET frontpage = EXCLUDED.frontpage;
`,
[req.body.oldid, req.body.newid]
)

Related

How to Check if value exists in sql column?

I want Chack If Value exists in coulmn, If value exist do not insert to table.
If not exist insert to table a new data.
I tried this but not works..
my code in node.js
`
//add new meeting
async function addNewMeeting(meeting: Meeting): Promise<Meeting>{
const sql = `INSERT INTO meetings Values (
DEFAULT,
${meeting.meeting_code},
'${meeting.meeting_start_date}',
'${meeting.meeting_end_date}',
'${meeting.meeting_description}',
'${meeting.meeting_room}'
)`;
const result:OkPacket = await dal.execute(sql);
meeting.id = result.insertId;
return meeting;
}
`
I tried to chack if the value - '2022-10-15 07:03:42' exist or not.
If not exists insert to table a new data.
if exist send a error that cannot insert a new meeting because there is already meeting at this time.
thanks :)
You can solve this at the SQL level by using the keyword UNIQUE when defining that column in the table. This will prevent you from being able to insert duplicate values.
SQL UNIQUE
Note that this will throw an error and depending on the package you are using to connect to your database, you might need some error handling.
Alternatively in your javascript you can select all values in the column that should be unique, and then only proceed with the insertion code if there is not a match.

How to prevent the sequelize from creating the output clause

When I do a create using sequelize it returns me the response i.e. the newly created entry row in the response,
Sequelize Create Object Code:
let createdObj= await sequelize.ModelName.create(modelObject,{ transaction :t, //more options can be added here, need some value of option that prevents the output inserted })
Below is the query created:
INSERT INTO [TABLE_NAME] ([COL1],[COL2],[COL3],[COL4]) OUTPUT INSERTED.* VALUES (#0,#1,#2,#3,#4)
Now I don't want the output clause to be part of the query, I want a simple insert like:
INSERT INTO [TABLE_NAME] ([COL1],[COL2],[COL3],[COL4]) VALUES (#0,#1,#2,#3,#4)
I don't want the output clause to be part of the query.
How can I achieve this in at the query level as well as at the model level? In some Create operations, I want the output clause and in some create operations, I don't want.
EDIT 1
On Further research I found an option called { returning: false } this does what is required i.e. create an insert query like this INSERT INTO [TABLE_NAME] ([COL1],[COL2],[COL3],[COL4]) VALUES (#0,#1,#2,#3,#4) but now the Sequelize is breaking because it's expecting those values back in return idk why?
C:\Users\MG265X1\project\node_modules\sequelize\lib\dialects\mssql\query.js:389
id = id || results && results[0][this.getInsertIdField()];
^
TypeError: Cannot read property 'id' of undefined
at Query.handleInsertQuery (C:\Users\MG265X1\project\node_modules\sequelize\lib\dialects\mssql\query.js:389:39)
Turns out if an autoIncrementAttribute is present in the model, it will look for the output clause, removing the attribute {autoIncrement: true } from the model hasn't helped as IDENTITY_INSERT cannot be null. How do I move ahead on this??
Edit 2 I could get it working with a combination of { returning: false } and {hasTriggers: true}. Have hasTriggers Attribute as true in your Model, this will allow you to single creates but for bulk Creates pass option returning: false at the time of bulkCreate.
Note: When using bulkCreate with { returning: false } you'll not be able to get the autogenerated Id, It's a trade-off that we had to live with as we want
bulkCreate to work with triggers, we ended up fetching the Id later from DB
Seems I raised this issue but was closed as it wasn't good SSCCE

Returning a single child's value on Firebase query using orderByChild and equalTo

I am trying to pull a URL for an image in storage that is currently logged in the firebase real time database.
This is for a game of snap - there will be two cards on the screen (left image and right image) and when the two matches the user will click snap.
All of my image urls are stored in the following way:
Each one has a unique child called "index" - I also have another tree that is just a running count of each image record. So currently I am running a function that checks the total of the current count, then performs a random function to generate a random number, then performs a database query on the images tree using orderByChild and an equalTo that contains the random index number.
If I log the datasnap of this I can see a full node for one record (So index, score, url, user and their values) however if I try to just pull the URL I get returned a value of Null. I can, rather annoyingly, return the term "URL" seemingly at my leisure but I can't get the underlying value. I've wondered if this is due to it being a string and not a numeric but I can't find anything to suggest that is a problem.
Please bare in mind I've only been learning Javascript for about a week at max, so if I'm making obvious rookie errors that's probably why!
Below is a code snippet to show you what I mean:
var indRef = firebase.database().ref('index')
var imgRef = firebase.database().ref('images')
var leftImg = document.getElementById('leftImg')
var rightImg = document.getElementById('rightImg')
document.addEventListener('DOMContentLoaded', function(){
indRef.once('value')
.then(function(snapShot){
var indMax = snapShot.val()
return indMax;
})
.then(function(indMax){
var leftInd = Math.floor(Math.random()* indMax + 1)
imgRef.orderByChild('index').equalTo(leftInd).once('value', function(imageSnap){
var image = imageSnap.child('url').val();
leftImg.src=image;
})
})
})
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
Your code needs to cater for that list, by looping over Snapshot.forEach():
imgRef.orderByChild('index').equalTo(leftInd).once('value', function(imageSnap){
imageSnap.forEach(function(child) {
var image = child.child('url').val();
leftImg.src=image;
})
})

WHERE col IN Query with empty array as parameter

From example where-col-in example and this answer, WHERE IN clauses should have query with parameters with following syntax
const response = await db.any('SELECT * FROM table WHERE id IN ($1:csv)', [data])
where data is an array.
Now, when data is an empty array, it produces the following query
SELECT * FROM users WHERE id IN ()
which is a syntax error.
Consider following statements:
this works
const x = await db.any('SELECT * FROM table WHERE id IN ($1:csv)', [[1, 2, 3]]);
this does not work
const y = await db.any('SELECT * FROM table WHERE id IN ($1:csv)', [[]]);
A similar error reported for squel library has answers on how knex and ruby's sequel behaves in such scenario.
Is this a bug or am I doing something wrong? Could there be an alternate syntax which works for both scenarios.
For instance, an alternate query using ANY works for both situations:
await db.any(`SELECT * FROM table WHERE id = ANY($1)`, [[1, 2, 3]]);
await db.any(`SELECT * FROM table WHERE id = ANY($1)`, [[]]);
What should be the best way to have WHERE col IN queries which could also handle empty arrays as params?
Library pg-promise gives you complete freedom in generating any SQL you want, it does not validate or control it in any way, as it is not an ORM.
CSV Filter is generic, it can be used in various context for generating queries. So when you are using it specifically for IN ($1:csv), it doesn't know it, and produces again generic output.
As per the comments I left in this issue, the right approach is to check whether you have any data in your array, and if not - do not execute the query at all. First, the query would be invalid, and even if you patch it with some empty logic, that means it won't generate any result, and executing such a query becomes a waste of IO.
let result = [];
if (data.length) {
result = await db.any('SELECT * FROM table WHERE id IN ($1:csv)', [data]);
}
/* else: do nothing */
Common Answer
Is this a bug or am I doing something wrong?
Not a bug, but a flaw for most SQL frameworks. It is very difficult to handle such parameters, so most frameworks just leave the empty list as it is to generate invalid SQL XXX in ().
Could there be an alternate syntax which works for both scenarios.
A simple approach is:
if(data is empty) data = [ -1 ] //fill a non-existing id
db.any('SELECT * FROM table WHERE id IN ($1:csv)', [data])
What about knex or sequel?
They are Query Builder frameworks, so they have chances to generate special SQL to handle empty lists. Popular methods used by Query Builder frameworks to handle WHERE id in () OR ...:
WHERE (id!=id) OR ...
WHERE (1=0) OR ...
WHERE (1!=1) OR ...
WHERE false OR ...
etc
Personally I do not like id!=id :)
For Some Framework
You may check its manual to see if there is some way to handle empty lists, eg: can the framework replace the empty list with a non-existing value?

Firebase dynamically change orderBy type

I am using Firebase to create a search function as follows
Firebase.database.ref('database-location').once('value').then(function(snapshot){
//do some filtering on results
});
However i want to dynamically sort the results using either:
.orderByKey()
or
.orderByChild('price')
I tried using bracket notation to select the above (the vars are decided from an if statment):
var orderByType = 'orderByChild'||'orderByKey'
var orderByVal = 'price'||undefined
Firebase.database.ref('database-location')[orderByType](orderByVal).once('value').then(function(snapshot){
//do some filtering on results
});
This works well for sort by value, but when using sort by key, firebase returns an error : "Query.orderByKey failed: Was called with 1 argument. Expects none."
Is there a way to dynamically remove the argument completely?
or any other way to switch between the two order by types?

Categories