Querying multiple rows using node-mysql - mysql

This issue pertains to node-mysql.
I seem to be having a problem with the following code, and it seems to be related to the use of user defined variables. The rendered query runs fine inside of any mysql IDE, returning multiple records. However when executed by node-mysql, it only returns a single record.
I've verified that eliminating the WHERE clause specifying T3.gender_rank creates predictable results in both node-mysql and my mysql IDE.
Has this issue been raised before, or is it something that I'm doing wrong?
var mysql = require('mysql'); // Establish SQL Support
var sql =
"select team, `div`, sum(points) AS teampoints "+
"from ( "+
" select "+
" *, "+
" (#genderRank := CASE WHEN #genderTMP <> gender THEN 1 ELSE #genderRank+1 END) AS gender_rank, "+
" (#genderTMP := gender) AS _gt "+
" from ( "+
" select * "+
" from racepoints "+
" WHERE "+
" ltrim(rtrim(race)) = '"+data.eventName+"' AND "+
" racedate = '"+getSimpleDate(new Date(data.eventStart))+"' "+
" ORDER BY team,gender,points DESC "+
" ) T1, "+
" (select #genderRank:=0 AS gender_rank_start) T2 "+
") T3 "+
"WHERE "+
" (T3.gender_rank <= 4 AND rtrim(ltrim(`div`)) = 'D2') OR "+
" (T3.gender_rank <= 3 AND rtrim(ltrim(`div`)) = 'D1') "+
"GROUP BY team, `div` "+
"ORDER BY `div`, teampoints DESC, team";
var db = new mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'admin',
database : 'nps',
multipleResults : true
});
db.connect();
db.query(
sql,
function(err,rows,fields){
if(err){
console.log(err);
return;
}
console.log(rows);
}
);
db.end();
The SQL database file is also available here: https://snipt.net/download/dde8b4b5ce8cd5fca21ac2334bae634f/-5369.sql

Instead of directly adding your variables to the sql string, let the mysql package do it for you. This usually solves problems like this one and additionally protects against SQL injection.
This is done using question marks (one for every variable) followed by an array of variables.
For example
connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
// ...
});

Related

How to correctly display in class data from joined sql tables?

I've started to learn SQL, I'd appreciate some insight and help on the below issue. My task is to: write a query in SQL workbench which returns names and surnames of users with more than 2 posts written (the query copied below). This part seems to work fine.
Then display in test class in a loop names and surnames of users that have published at least 2 posts.
How to write a code that creates that query in the test class? Basically I get syntax error and I'm not sure how it should look like("Column 'POSTS_NUMBERS' not found.").
(then another part of exercise follows - add posts and then check by assertion if the actual number of records in the data base is the same as result of the query)
SELECT USERS.FIRSTNAME, USERS.LASTNAME, USERS.ID, COUNT(*) AS POSTS_NUMBER
FROM USERS
JOIN POSTS ON USERS.ID = POSTS.USER_ID
GROUP BY POSTS.USER_ID
HAVING COUNT(*) >= 2;
#Test
public void testSelectUsersAndPosts() throws SQLException {
//given
DbManager dbManager = DbManager.getInstance();
String countQuery = "SELECT COUNT(*) FROM USERS"; //IS THIS PART CORRECT?
Statement statement = dbManager.getConnection().createStatement();
ResultSet rs = statement.executeQuery(countQuery);
int count = 0;
while (rs.next()) {
System.out.println(rs.getInt("POSTS_NUMBERS") + ", " +
rs.getString("FIRSTNAME") + ", " +
rs.getString("LASTNAME"));
}
String sql = "INSERT INTO POSTS(USER_ID, BODY) VALUES ('3', 'I am Mark')";
statement.executeUpdate(sql);
sql = "INSERT INTO POSTS(USER_ID, BODY) VALUES ('3', 'hey!')";
statement.executeUpdate(sql);
//when
String sqlQuery = "SELECT * FROM USERS";
statement = dbManager.getConnection().createStatement();
rs = statement.executeQuery(sqlQuery);
//then
int counter = 0;
while (rs.next()) {
System.out.println(rs.getInt("USERS.ID") + ", " +
rs.getString("FIRSTNAME") + ", " +
rs.getString("LASTNAME"));
counter++;
int expected = count + 1;
Assert.assertEquals(expected, counter);
rs.close();
statement.close();
}
}

Node js - Mysql query is not executed as coded

i created several sql statements in node.js and now i want to execute them on my db. However, the query string is not executed as coded.
This is my function to generate the query string.
function insertProducts(products) {
if (!connection) {
// Create MYSQL-Connection
console.log('BUILDING connection to DB');
connection = getConnection();
connection.connect();
}
let query = "";
for (let i = 0; i < products.length; i++) {
// Iterate trough the products array and create a sql query
query += "INSERT INTO `tShortDescription`(`ShortDescription`, `Language`) VALUES ('" + products[i].short_description + "', 'DE'); " +
"INSERT INTO `tDescription`(`Description`, `Language`) VALUES ('" + products[i].description + "', 'DE'); " +
"INSERT INTO `tManufacturer`(`Name`) VALUES ('" + products[i].manufactur + "'); " +
"INSERT INTO `tSupplier`(`Name`) VALUES ('" + products[i].supplier + "'); " +
"INSERT INTO `tProduct`(`Sku`, `Title`, `ShortDescriptionId`, `DescriptionId`, `WohlesalePrice`, `SellingPrice`, `Quantity`, " +
"`ManufacturerId`, `SupplierId`, `Ean`) VALUES ('" + products[i].sku + "', '" + products[i].name + "', " +
"(SELECT id FROM tShortDescription WHERE ShortDescription = '" + products[i].short_description + "' LIMIT 1), " +
"(SELECT id FROM tDescription WHERE Description LIKE '" + products[i].description + "' LIMIT 1), " +
products[i].wholesale_price + ", " + products[i].selling_price + ", " + products[i].quantity + ", " +
"(SELECT id FROM tManufacturer WHERE Name = '" + products[i].manufactur + "' LIMIT 1), " +
"(SELECT id FROM tSupplier WHERE Name = '" + products[i].supplier + "' LIMIT 1), " + products[i].ean + "); ";
for (let j = 0; j < products[i].categories.length; j++) {
// Ad all categories to query
query += "INSERT INTO `rtCategory`(`ProductId`, `CategoryId`) " +
"VALUES ((SELECT `Id` FROM `tProduct` WHERE sku = '" + products[i].sku + "' LIMIT 1), " +
"(SELECT `Id` FROM `tCategory` WHERE Id = " + products[i].categories[j].src + " LIMIT 1)); "
for (let c = 0; c < products[i].images.length; c++) {
// Ad all images to query
query += "INSERT INTO `tImage`(`Url`) VALUES ('" + products[i].images[c].src + "'); " +
"INSERT INTO `rtImage`(`ProductId`, `ImageId`) " +
"VALUES ((SELECT `Id` FROM `tProduct` WHERE sku = '" + products[i].sku + "' LIMIT 1), " +
"(SELECT `Id` FROM `tImage` WHERE url = '" + products[i].images[c].src + "' LIMIT 1)); "
}
}
}
query = query.replace(/[\n\r\t]/g,);
if (query != "") {
// Create new Product in DB
return new Promise((resolve, reject) => {
connection.query(query, function (error, results, fields) {
if (error) { console.log(error) };
console.log('INSERTING successful');
resolve(results);
});
});
} else {
console.log('There are no new products to insert in db');
}
}
If i console.log(query) (before the query is ecexuted on my db) and execute the string directly in php myadmin, everything works fine but if i execute the query in code like connection.query(query, function (error, results, fields)....., i got several errors.
Error msg in terminal:
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO `tDescription`(`Description`, `Language`) VALUES ('<p><strong>Tantra' at line 1",
sqlState: '42000',
index: 0,
I also get the sql query returned in terminal because of the error, and if i execute this query directly in php myadmin i also get an error ->
SQL query: Documentation
INSERT INTO `rtImage`(`ProductId`, `ImageId`) VALUES ((SELECT `Id` FROM `tProduct` WHERE sku = 'H1500148' LM
IT 1), (SELECT `Id` FROM `tImage` WHERE url = 'https://cdnbigbuy.com/images/H1500148_409897.jpg' LIMIT 1))
MySQL said: Documentation
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LM
IT 1), (SELECT `Id` FROM `tImage` WHERE url = 'https://cdnbigbuy.com/images' at line 1
It looks as if the LIMIT is somehow divided ...use near 'LM IT 1)....
I hope you understand where the problem is and someone might have a tip.
Your query is processed as 'LIMIT' it's just a new line in the console where the error showed up.
You should not be using string concatenation (or even template literals) for SQL queries under any circumstances because 1. It very likely the source of your problem. 2. It's very dangerous as it allows SQL injection attacks.
Use parameters instead. Here's a example:
connection.query("SELECT * FROM bank_accounts WHERE dob = ? AND bank_account = ?",[
req.body.dob,
req.body.account_number
],function(error, results){});
To read more about SQL injections and placeholders read this article.
Thanks for the helpful tips.
The problem was that I didn't set multiple statements: true in my code. This var is by default false and should be true, otherwise it is not possible to execute several queries once at a request!

How to solve? ER_BAD_FIELD_ERROR: Unknown column 'undefined' in 'field list'

I am trying to insert form data into MySQL database in nodejs using expressjs
When I run my code in command prompt it ran well but when I press the submit button, I got the following errors:
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password:'',
database : 'test'
});
app.get("/", function(req, res){
res.render("home");
});
//when I press submit button it should post the request and render a page to submit route with text "data saved!!"
app.post("/submit", function(req, res){
var q = "Insert into test (ID, name, crash1, crash2, crash3) VALUES (null, '" + req.body.ANR + "', " + req.body.crash1 + ", " + req.body.crash2 + ", " + req.body.crash3 +")";
connection.query(q, function(err){
if(err) throw err
res.render("home", {message: 'data saved!!'});
})
});
I created a table in MySQL Command line
create table xyz(
ID BIGINT AUTO_INCREMENT PRIMARY KEY NOT NULL,
name VARCHAR(100) NOT NULL,
crash1 BIGINT,
crash2 BIGINT,
crash3 BIGINT
);
when I inserted manually it worked!
insert into xyz(ID, name, crash1, crash2, crash3) VALUES (1,'REERE', 2 ,2 ,2);
my error looks like this
You are inserting into test table in your code:
var q = "Insert into test (ID, name, crash1, crash2, crash3) VALUES (null, '" + req.body.ANR + "', " + req.body.crash1 + ", " + req.body.crash2 + ", " + req.body.crash3 +")";
But table name is xyz. You should replace test by xyz and it should work.
And don't pass null in id as well as id is not null.
Please convert crash1, crash2, crash3 into int value:
req.body.crash1 = parseInt(req.body.crash1);
req.body.crash2 = parseInt(req.body.crash2);
req.body.crash3 = parseInt(req.body.crash3);
It should be like:
var q = "Insert into xyz (name, crash1, crash2, crash3) VALUES ('" + req.body.ANR + "', " + req.body.crash1 + ", " + req.body.crash2 + ", " + req.body.crash3 +")";

Mysql NodeJs syncronous queries

Thank you for the answer,
I did that : i used "sync-mysql" :
but now its very very slow...
Maybe i could do the same code using Mysql NPM
Do you know how my code must look like if I want to use asyncronous function and doing the same thing as below ? It will help me a lot :)
I have almost finished my project and I only have this function left
const customer_booked = []
customer_booked[0] = []
customer_booked[1] = []
let sql = "SELECT * " +
"FROM customer as C " +
"WHERE customer_reference REGEXP '^[c]i*' "
if (filters[0].value.length){
sql += "AND C.customer_name LIKE '%" + filters[0].value + "%' "
}
if (filters[3].value.length){
sql += "LIMIT " + filters[3].value
}
var result = connection.query(sql);
const customers = [];
const booked = connection.query('SELECT cr.customer_id, a.codeAgent ' +
'FROM customer_reservation as cr ' +
'INNER JOIN agent as a ' +
'ON a.id = cr.agent_id')
booked.forEach(customer_booking => {
customer_booked[0].push(customer_booking.customer_id)
customer_booked[1].push(customer_booking.codeAgent)
});
result.forEach( customer => {
var months;
let d1 = new Date(customer.last_order);
let d2 = new Date();
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
months += d2.getMonth();
months = months <= 0 ? 0 : months;
if (customer_booked[0].includes(customer.customer_id)){
let code_agent_index = customer_booked[0].indexOf(customer.customer_id)
customer.available = 'booked'
customer._rowVariant = 'warning'
customer.agent_code = customer_booked[1][code_agent_index]
}
else if (months >= 12){
customer.available = 'available'
customer._rowVariant = 'success'
} else {
customer.available = 'notAvailable'
customer._rowVariant = 'danger'
}
let sql2 = "SELECT * " +
"FROM customer_addresses AS CA " +
"WHERE CA.customer_id = " + customer.id
customer.addresses = connection.query(sql2)
customers.push(customer);
//customers[customers.length].push()
})
callback(false, result)
You can use node.js async/await using IIFE, like this:
(async() => {
const users = await getUsers();
for(const user of users){
user.addresses = await getAddresses(user.id);
// your other code just translated to JS.
}
return users;
})()
So, the main idea is to await your async code.
For example we use IIFE (Immediately Invoked Function Expression) to access needed async/await and for tests.
In real code you should name functions with keyword async
Here is nice tutorials which could explain how to use async/await 1, 2

inserting reservation to database

This has been driving me crazy and I'm sure it's something simple. I'm getting a 'values must contain at least one element' error from server when I try to input a reservation from the table that comes up. It's all running ok. No matter if I use quotes in the VALUES section or plus(+)symbols or quotes over the separating commas I get different error messages. When I put quotes over table_num I get and error telling me that you cant insert CHAR into INTEGER. When I remove quotes I get error telling me -
Severe: java.sql.SQLSyntaxErrorException: Column 'TABLE_NUM' is either not in any table in the FROM list or appears within a join specification etc. Could anyone tell me what is going on? Here's the jsp code. Thanks in advance.
<%
int tableNum = 0;
String firstName = null;
String lastName = null;
String Address = null;
int Phone = 0;
java.sql.Date date = null;
int People = 0;
if (request.getParameter("table_num")!=null){
tableNum = Integer.parseInt(request.getParameter("table_num"));
}
if (request.getParameter("first")!=null){
firstName = request.getParameter("first");
}
if (request.getParameter("last")!=null){
lastName = request.getParameter("last");
}
if (request.getParameter("address")!=null){
Address = request.getParameter("address");
}
if (request.getParameter("phone")!=null){
Phone = Integer.parseInt(request.getParameter("phone"));
}
if (request.getParameter("date")!=null){
java.util.Date utilDate = new java.util.Date(request.getParameter("date"));
date = new java.sql.Date(utilDate.getTime());
}
if (request.getParameter("people")!=null){
People = Integer.parseInt(request.getParameter("people"));
}
if(tableNum != 0 && firstName != null && lastName != null && Address != null && Phone != 0 && date != null && People != 0){
String URL = "jdbc:derby://localhost:1527/Reservations";
String USERNAME= "johnpaul";
String PASSWORD= "purlease";
Connection myCon = null;
Statement ste = null;
PreparedStatement preparedStmt = null;
try{
Class.forName("org.apache.derby.jdbc.ClientDriver");
System.out.println("Connecting to DB...");
Connection con=DriverManager.getConnection("jdbc:derby://localhost:1527/Reservations","johnpaul", "purlease");
System.out.println("Connected successfuly");
System.out.println("Inserting records into table");
Statement st = con.createStatement();
String query = "INSERT INTO JOHNPAUL.CUSTOMER_RESERVATIONS(TABLE_NUM,FIRST_NAME,LAST_NAME,ADDRESS,TELEPHONE,DATE,NUMBER_IN_PARTY)VALUES(table_num,first,last,address,phone,date,people)";
st.executeUpdate (query);
System.out.println("Records inserted");
}catch(SQLException se){
se.printStackTrace();
}catch(ClassNotFoundException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}
}
%>
Your problem appears to be here:
String query = "INSERT INTO JOHNPAUL.CUSTOMER_RESERVATIONS
(TABLE_NUM, FIRST_NAME,LAST_NAME,ADDRESS,TELEPHONE, DATE, NUMBER_IN_PARTY)
VALUES (table_num, first,last,address,phone,date,people)";
Two things here:
1. Escape your strings; and
2. Concatenate the values in your variables to the string.
String query = "INSERT INTO JOHNPAUL.CUSTOMER_RESERVATIONS
(TABLE_NUM, FIRST_NAME,LAST_NAME,ADDRESS,TELEPHONE, DATE, NUMBER_IN_PARTY)
VALUES (" + table_num + ", '" + first + "', '" + last + "', '" + address + "', " + phone + " , '" + date + "', " + people + ");";
You may have to verify the format that your database engine expects the date field.