I am a beginner in mySQL and I am trying to create a user's table with information about the user (see code) and populate a column with details that I get from a new table that gets created.
Now I want to be able to put some information from the 'creditcards' table like number for example, to the 'users' table which includes a column 'creditcard', so that I can see each user's credit card number.
I am also comparing the name of the user with the name of the credit card owner so it populates the table according to the user.
I couldn't find any information about the specific problem I am having here.
Here's how I am trying to write:
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'INSERT INTO users (creditcard) SELECT number,name FROM creditcards WHERE users.name = creditcards.name';
const userCreateModel = `
CREATE TABLE IF NOT EXISTS users (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NOT NULL,
username VARCHAR(45) NOT NULL,
email VARCHAR(45) NOT NULL,
phonenumber VARCHAR(45) NOT NULL,
password VARCHAR(255) NOT NULL,
creditcard INT(11),
salt VARCHAR(255),
created_at DATE,
update_at DATE,
deleted_at DATE,
lastSignIn DATE,
PRIMARY key (id)
)
`;
const CreditCardModel = `
CREATE TABLE IF NOT EXISTS creditcards (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR (25) NOT NULL,
type VARCHAR(10) NOT NULL,
number INT(12) NOT NULL,
expiration DATE,
svss INT(3) NOT NULL,
created_at DATE,
PRIMARY key (id)
)
`;
I am trying to create a user named ula and then a credit card with the name ula (and all other columns) which I am sending from postman.
The credit card part in nodejs looks like this:
const createCreditCard = async (req, res, next) => {
const {
name,
type,
number,
expiration,
svss
}: {
name: String,
type: String,
number: String,
expiration: String,
svss: String
} = req.body;
const createAt = new Date(Date.now());
try {
const createNewCreditCard = 'INSERT INTO creditcards (name, type, number, expiration, svss) VALUES (?,?,?,?,?)';
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=' + number + ' WHERE name="' + name + '"';
console.log(results);
}
});
res.status(201).send({ success: true, message: 'New credit card was created', data: {name, type, number, expiration, svss} });
} catch (error) {
res.status(500).send({ success: false, message: 'Server error' });
}
await next;
}
The server returns 201, I go to mysql, open users, see column creditcard and its NULL.
Because the entry already exists in the database for users table, you should use UPDATE instead of INSERT.
An example that should work with your code (you already know name and number as vars because you just created the credit card info with them, no need to select them again):
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=' + number + ' WHERE name="' + name + '"';
EDIT: this is the new code from your edit. You already use prepared statements, so forget my notice about that. I've updated the query to follow this. What was missing in your code is that you need to actually do the query! Only declaring the constant won't do anything to your database..
try {
const createNewCreditCard = 'INSERT INTO creditcards (name, type, number, expiration, svss) VALUES (?,?,?,?,?)';
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
const JoinCreditCard = 'UPDATE users SET creditcard=? WHERE name=?';
con.query(JoinCreditCard, [number, name], (err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
}
});
}
});
res.status(201).send({ success: true, message: 'New credit card was created', data: {name, type, number, expiration, svss} });
} catch (error) {
res.status(500).send({ success: false, message: 'Server error' });
}
NOTE: you should know that using the name to reference the credit card will not allow you to have multiple credit cards for one user, and should be careful about users with the same name, or else this query will update both users. It would be safer to always use the user id field in the WHERE clause. (you should know it at this point)
THIS IS WHAT I RECOMMEND:
it's usually better that the creditcard in users only stores the id from the creditcards table. Like this, relations are on the primary key and it's more optimized (you need to get the id after the credit card creation request, in an inner SELECT in following code).
use the ids to identify rows updates, to prevent 2 users to be updated
delete name from creditcards table, it's already in users
having a third table to reference the relations like states user1974729 is not mandatory, however, it will be the case if you conveniently want to be able to have more than one credit card per user or more than one user that share a card (1 to n relation)
code:
//relation based on id instead of number stored in users + name removed. I assume at this point, you know the id of your user (in var "id" used below in `WHERE` clause)
con.query(createNewCreditCard, [type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=(SELECT id FROM creditcards WHERE type="' + type + '" AND number="' + number + '" AND expiration="' + expiration + '" AND svss="' + svss + '") WHERE id="' + id + '"';
//no change in userCreateModel
//deleted "name" in CreditCardModel
const CreditCardModel = `
CREATE TABLE IF NOT EXISTS creditcards (
id INT(11) NOT NULL AUTO_INCREMENT,
type VARCHAR(10) NOT NULL,
number INT(12) NOT NULL,
expiration DATE,
svss INT(3) NOT NULL,
created_at DATE,
PRIMARY key (id)
)
`;
it is important that the tables are in normalized forms.
There should be 3 tables.
Users -- all the user data
Credit cards -- all the credit card related information.
Users credit card map -- map users to credit card information.
Related
I have three tables with data schema, like:
TABLE user (
user_id BINARY(16) PRIMARY KEY NOT NULL,
created DATETIME NOT NULL,
last_updated DATETIME,
coordinator BINARY(16),
num_updates INT NOT NULL
);
TABLE summary (
user_id BINARY(16) PRIMARY KEY NOT NULL,
calculation_time DATETIME NOT NULL,
calculation_method VARCHAR(25) NOT NULL,
label VARCHAR(50) NOT NULL,
critical_count INT NOT NULL,
median_risk FLOAT(10)
);
TABLE actions(
user_id BINARY(16) PRIMARY KEY NOT NULL,
label VARCHAR(50) NOT NULL,
access_count INT NOT NULL,
median FLOAT(10)
);
The data for all the users (user table) is simply fetched using the lambda handler function in the following manner:
const AWS = require('aws-sdk');
const rdsDataService = new AWS.RDSDataService();
module.exports.hello = async (event, context, callback) => {
const req_id = "5a9dbfca-74d6-471a-af27-31beb4b53bb2";
const sql = 'SELECT * FROM user WHERE user_id=:id';
try {
const params = {
resourceArn: 'arn:aws:rds:us-west-********************',
secretArn: 'arn:aws:secretsmanager:us-west**************',
sql,
database: 'dev_db1',
continueAfterTimeout: true,
includeResultMetadata: true,
parameters: [{ 'name': 'id', 'value': { 'stringValue': `${req_id}` } }]
}
const db_res = await rdsDataService.executeStatement(params).promise();
const convertToJson = (dbresponse) => {
const columns = dbresponse.columnMetadata.map(col => col.name);
const row_data = dbresponse.records.map(row => {
const json_obj = {};
row.map((val, i) => {
json_obj[columns[i]] = Object.values(val)[0];
});
return json_obj;
});
return row_data;
};
const modified_data = convertToJson(db_res);
const response = {
body: {
statusCode: 200,
message: 'Data fetched successfully',
data: modified_data,
}
};
callback(null, response);
} catch (error) {
console.log('Error Received', error);
const error_res = {
body: {
statusCode: error.statusCode,
message: error.message,
data: null
}
}
callback(null, error_res);
}
};
If the same is followed for another table summary or actions, it also works. Now, I need to combine all the columns of these three tables and then return the data (returned rows should match on the basis of req_id).
My working snippet: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=016ecc94c792611fbaca810605e81a6a
But the final result obtained contains the column user_id in duplicated form i.e. three times inclusion. I don't need the same column to be repeated thrice.
I am a bit new to handling MySQL queries, so unable to figure out the exact reason for the error even when the table exists. The MYSQL version used in Aurora is 5.7.
Any help to resolve the same is appreciated!
Plan A: Explicitly specify the columns you want. Extra benefit: You can get rid of the ids, which tend to be useless to others reading the output.
Plan B: (This option is not always possible.) Instead of JOIN .. ON t1.a = t2.a, say JOIN .. USING(a)
I like to use short aliases. Here's doing all things together:
SELECT u.last_name, u.first_name,
s.risk_score,
t.likes
FROM user AS u
JOIN summary AS s USING(user_id)
LEFT JOIN test AS t USING(user_id)
In general, it is not wise to have a 1:1 relationship (as you have via user_id); you may as well have all the columns in a single table.
try this
SELECT users.*, summary.* from users, summary WHERE users.user_id = summary.user_id
OR
SELECT * from users, summary WHERE users.user_id = summary.user_id
Can someone tell me what is wrong with this code? I am getting syntax error near Select category_ID;
I am using latest version is mysql in nodejs
Note - If i remove the output params, Input code is properly working.
Node Server Code -
app.post('/api/createcategory', function (req, res) {
name = req.body.categoryName, icon = req.body.categoryIcon;
let createcategory = `CALL spAddCategory(?, ?, #category_id); SELECT #category_id;`
db.query(createcategory, [name, icon], (err, result) => {
if(err) {throw err};
console.log(result);
})
res.send('Category Created')
})
SQL Query -
CREATE PROCEDURE spAddCategory ( IN category_name varchar(255), IN category_icon varchar(255), OUT category_id int )
BEGIN
INSERT INTO categories ( categoryName, categoryIcon )
VALUES ( category_name, category_icon );
SELECT categoryID INTO category_id FROM categories
WHERE categoryName = category_name;
END
Instead of OUT-variables (which are useful mainly between procedures), consider handling the output as normal result set:
app.post('/api/createcategory', function (req, res) {
name = req.body.categoryName, icon = req.body.categoryIcon;
let createcategory = `CALL spAddCategory(?, ?);`
db.query(createcategory, [name, icon], (err, result) => {
if(err) {throw err};
console.log(result[0]);
})
res.send('Category Created')
})
And the procedure, returns the result set which contains the last inserted id (assuming the categoryID is an AUTO_INCREMENT id):
CREATE PROCEDURE spAddCategory (
category_name varchar(255),
category_icon varchar(255)
)
BEGIN
INSERT INTO categories ( categoryName, categoryIcon )
VALUES ( category_name, category_icon );
SELECT last_insert_id();
END
Note that you may end up with more than one category with same name.
I have created a simple CRUD application with ExpressJS and MySQL. What I am trying to do is to show the "Users Name" of a specified post, based on which user created that post.
I have 2 tables... posts & users. The posts table has an author column that fills with the users ID when a post is created.
I am able to make the specific "Post" show its data based on the post ID (i.e Post Title & Post Body). However when I try to show the "Users Name" based on which user created that specific post it shows every "Users Name" inside of the users table.
Can anyone help me so that when I view a specific post it will only show the correct "Users Name" based on the posts that that user has created?
My code is below:
posts.js
// Read A Post
router.get('/:id', (req, res, next) => {
let sql = `SELECT * FROM posts WHERE id = ${req.params.id}`;
let query = db.query(sql, (error, result) => {
if(error) throw error;
db.query(`SELECT name FROM users`, (error, userName) => {
if(error) throw error;
res.render('post', {
posts: result,
author: userName
});
});
});
});
posts.pug
extends layout
block content
ul.list-group
each post in posts
li.list-group-item
h1= JSON.stringify(post.title)
h3= JSON.stringify(author)
p= JSON.stringify(post.body)
a.btn.btn-primary.float-right(href='/posts/update/' + post.id) Update
a.btn.btn-danger.float-right(href='/posts/delete/' + post.id) Delete
posts Schema
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
title varchar(255) YES NULL
body varchar(255) YES NULL
author varchar(255) YES NULL
users Schema
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
name varchar(255) YES NULL
email varchar(255) YES NULL
username varchar(255) YES NULL
password varchar(255) YES NULL
Any help is appreciated. Thank you.
in the code you make 2 independent queries:
1) select relevant posts
2) select all users
use the Inner Join to achieve what you want.
https://www.w3schools.com/sql/sql_join_inner.asp
your code will look smth like this:
// Read A Post
router.get('/:id', (req, res, next) => {
let sql = `SELECT * FROM posts INNER JOIN users ON posts.userid= users.id WHERE posts.id = ${req.params.id} `;
let query = db.query(sql, (error, result) => {
if(error) throw error;
res.render('post', {
posts: result,
author: result
});
});
});
I am working on a node js app which makes use of the express and mysql libraries.
I have a MySQL user table with the following columns:
auto incrementing primary id
username varchar unique
There is no password, etc.
Other tables include:
room
id
room_name
user_room
id
user_id (FK to user table)
room_id (FK to room table)
details
id
user_room_id (FK to user_room table)
col1
col2
col3
Upon trying to connect to a room, I want the database to try pulling their data for that room.
If the data does not exist, I want to see if the username exists in the user table.
If the username does exist, I want to get their id.
If the username does not exist, I want to add their name to the user table and capture the last inserted id
Once having their id, I want to add a record to the user_room table for that user and then several records to the details table based on the newly inserted id in the user_room table.
I seem to be getting into a tangled web going into so many layers.
This is what my code currently looks like:
socket.on('enter room', function(data, callback){
var sql = "select col1, col2, col3 from room JOIN user_room on room.id = user_room.room_id JOIN user on user_room.user_id = user.id JOIN details on user_room.id = details.user_room_id where username = ?";
db_connection.query(sql, [socket.nickname], function (err, result) {
if (err){
console.log("ENTER ROOM DB ERROR: " + err);
return;
}
if (!result.length){
var sql = "select id from user where name = ?";
db_connection.query(sql, [socket.nickname], function (err, result){
if (err){
console.log("ENTER ROOM, SELECT ID DB ERROR: " + err);
return;
}
if (!result.length){
var sql = "insert into user (name) values (?)";
db_connection.query(sql, [socket.nickname], function(err, result){
if (err){
console.log("ENTER ROOM, INSERT ID DB ERROR: " + err);
return;
}
id = result.insertId;
});
}
else {
id = result[0].id;
}
});
//We need to pull things back into one branch again here
//Using the user id and room id I will insert a record into the user_room table
//Then using the newly inserted id in the user_room table, I need to add records to a details table
}
});
//Send col1, col2, and col3 data back to user
//This section here also needs to be pulled back into one branch again
io.sockets.emit('details', result);
});
It mostly works, but because I branch off in two different ways to get the user id (one if it already exists, and one if I need to insert it), I do not know how to pull it back together again into one branch.
What can I do to pull my code back into one branch again so that I can use the id again? Or, is there a better way of approaching this altogether?
A side question: Can I safely remove the "callback" in my opening function, or should I be using this somewhere in my code? I feel that the emit is like a callback to the client so that I do not need "callback" here.
I took a different approach to get userId on upsert. I used promise to send the room data immediately, if available.
socket.on('enter room', function (data, callback) {
let nickName = '';
let roomId = '';
return bookingDetails(nickName).then((details) => {
if (details.length !== 0) {
return Promise.resolve(details);
} else {
return createRoom(nickName, roomId);
}
}).then((details) => {
io.sockets.emit('details', details);
});
});
function createRoom(nickName, roomId) {
return getUserDetails(nickName).then((userId) => {
return insertUserRoom(userId, roomId); //your function
}).then((userRoomDetails) => {
return insertDetails(userRoomDetails); //your function
});
}
function bookingDetails(nickName) {
let sql = "select col1, col2, col3 from room " +
"JOIN user_room on room.id = user_room.room_id " +
"JOIN user on user_room.user_id = user.id " +
"JOIN details on user_room.id = details.user_room_id where username = ?";
return new Promise((resolve, reject) => {
db_connection.query(sql, [nickName], function (err, details) {
if (err) {
return reject("ENTER ROOM DB ERROR: ");
}
return resolve(details);
});
});
}
function getUserDetails(nickName) {
return new Promise((resolve, reject) => {
let sql = "select id from user where name = ?";
db_connection.query(sql, [nickName], function (err, userDetail) {
if (err) {
return reject(err);
}
if (userDetail === null) { //insert
return createUser(nickName);
}
return userDetail;
}).then((userDetail) => {
return resolve(userDetail.id);
});
});
}
function createUser(nickName) {
return new Promise((resolve, reject) => {
let sql = "insert into user (name) values (?)";
db_connection.query(sql, [nickName], function (err, userDetail) {
if (err) {
return reject(err);
}
return resolve(userDetail);
});
});
}
Basically I have two table
User -> id, name , email , fname, lname etc...
Device -> id, name, user_id, etc......
here first I will insert data into User table and I get result,
from that result how to get the Id of the User table entry so that I can use is as user_id for the entry in device
basically user_id is foreign key referring User table
My insert code goes like this
exports.user = function(req,res){
var user_email = req.param('email', null);
var user_fname = req.param('fname', null);
var user_lname = req.param('lname', null);
var user_phone = req.param('phone', null);
var user_description = req.param('description',null);
var user_data = {
table:TABLE_USER,
data:{
'email':user_email,
'fname':user_fname,
'lname':user_lname,
'phone':user_phone,
'description':user_description
}
}
db.insert(user_data,function (result) {
//How to get the ID of the last inserted row from result,
// get Id and insert in device table
res.writeHeader(200, {"Content-Type": "text/plain"});
res.write(result[0] + " ");
res.end();
}
);
}
Just have a look at the documentation : Getting the id of an inserted row
Their code example :
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function(err, result) {
if (err) throw err;
console.log(result.insertId);
});