I am very new to NodeJS, but I have been working to use it to serve my Angular project. I need to access an Oracle DB and return some information using a select statement. I have one statement that works correctly using a bind parameter that is set up like this:
var resultSet;
connection.execute("SELECT column_name, decode(data_type, 'TIMESTAMP(3)','NUMBER'"
+ ",'VARCHAR2','STRING','CHAR', 'STRING','NUMBER') as \"DATA_TYPE\""
+ "FROM someTable where table_name = :tableName",
[table], //defined above
{outFormat: oracledb.OBJECT},
function (err, result) {
if (err) {
console.error(err.message);
doRelease(connection);
return;
}
resultSet = result.rows;
console.log("Received " + resultSet.length + " rows.");
res.setHeader('Content-Type', 'application/json');
var JSONresult = JSON.stringify(resultSet);
// console.log(JSONresult);
res.send(JSONresult);
doRelease(connection);
});
This returns exactly what I want it to, with the bound variable being what I wanted it to be. Below is the code that doesn't work:
var resultSet;
connection.execute(
"SELECT DISTINCT :columnName from someTable",
['someColumn'],
{outFormat: oracledb.OBJECT},
function (err, result) {
if (err) {
console.error(err.message);
doRelease(connection);
return;
}
resultSet = result.rows;
console.log("Received " + resultSet.length + " rows.");
res.setHeader('Content-Type', 'application/json');
var JSONresult = JSON.stringify(resultSet);
console.log(JSONresult);
res.send(JSONresult);
doRelease(connection);
});
This returns {":COLUMNNAME": "someColumn"}. I do not understand why it won't display the results correctly. The two snippets of code are exactly the same, save the SQL query part. I know this a long question, but I really need help. Thank you!
You can bind data values, not the text of the statement itself.
Related
I am trying to post my inputs to my SQL Server database. I can in fact POST to the database, but I get back a blank response. I know it's because I am returning "Success" instead of my variables but how to I correctly format that for the return statement?
POST method:
[HttpPost]
public JsonResult Post(Weather Wea)
{
string query = #"INSERT INTO dbo.Information (Date, TemperatureC, TemperatureF, Summary) VALUES ('" + Wea.Date + #"'
,'" + Wea.TemperatureC + #"'
,'" + Wea.TemperatureF + #"'
,'" + Wea.Summary + #"'
)";
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString("WeatherAppCon");
SqlDataReader myReader;
using (SqlConnection myCon = new SqlConnection(sqlDataSource))
{
myCon.Open();
using (SqlCommand myCommand = new SqlCommand(query, myCon))
{
myReader = myCommand.ExecuteReader();
table.Load(myReader);
myReader.Close();
myCon.Close();
}
}
return new JsonResult("Success");
}
Front-end POST
export class PostDataComponent {
baseUrl: string;
date: number;
temperatureC: number;
summary: string;
weatherForm: FormGroup;
constructor(public http: HttpClient, #Inject('BASE_URL') baseUrl: string, private formBuilder: FormBuilder) {
this.baseUrl = "https://localhost:44347/WeatherForecast";
this.weatherForm = formBuilder.group({
Date: new FormControl(),
TemperatureC: new FormControl(),
Summary: new FormControl()
});
}
CreateData() {
const params = new HttpParams({
fromObject: {
'date': this.weatherForm.value.Date.toString(),
'temperatureC': this.weatherForm.value.TemperatureC.toString(),
'summary': this.weatherForm.value.Summary.toString()
}
});
console.log(params);
this.http.post(this.baseUrl, {},{ params: params }).subscribe(data => {
console.log(data);
});
}
}
Couple things here.
As marc_s commented, you should be using parameterization instead of concatenating to avoid any potential SQL injection:
string query = #"INSERT INTO dbo.Information (Date, TemperatureC, TemperatureF, Summary) VALUES (#Date, #TemperatureC, #TemperatureF, #Summary)";
...
using (System.Data.SqlClient.SqlCommand myCommand = new SqlCommand(query, myCon))
{
myCommand.Parameters.AddWithValue("#Date", Wea.Date);
myCommand.Parameters.AddWithValue("#TemperatureC", Wea.TemperatureC);
myCommand.Parameters.AddWithValue("#TemperatureF", Wea.TemperatureF);
myCommand.Parameters.AddWithValue("#Summary", Wea.Summary);
...
Unless you have a trigger on your target table with an output, your query isn't returning any data (just the number of rows inserted) and your SqlDataReader is empty. You could get rid of the reader/DataTable and use myCommand.ExecuteScalar() instead in this case. If you do have a trigger outputting the inserted data, disregard this.
If you don't have an output trigger but do still need to return the inserted values for whatever reason, you could keep your SqlDataReader and update your query to the following
string query = #"INSERT INTO dbo.Information (Date, TemperatureC, TemperatureF, Summary)
OUTPUT inserted.Date,inserted.TemperatureC,inserted.TemperatureF,inserted.Summary
VALUES (#Date, #TemperatureC, #TempreatureF, #Summary)";
Without knowing the response format you're looking for, it's hard to give an answer on how to generate it. If you need to return the inserted values, you could use the OUTPUT keyword as in the previous bullet and serialize your DataTable.
I am writing API which insert into a table with multiple rows, I am using UNNEST to make it work.
What I have done:
in js file:
api.post(PREFIX + '/class/insert', function (request) {
var db = pgp(dbconnect);
//Params
var data = request.body; //should be an array
var classes = [];
var starts = [];
var ends = [];
for (var i = 0; i < data.length; i++) {
classes.push(data[i].class_id);
starts.push(data[i].timestamp_start);
ends.push(data[i].timestamp_end);
}
const PQ = require('pg-promise').ParameterizedQuery;
var sql =
"INSERT INTO sa1.class(class_id, timestamp_start, timestamp_end) " +
"VALUES( "+
"UNNEST(ARRAY" + JSON.stringify(classes).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(starts).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(ends).replace(/"/g, "'") + ")"
const final_sql = new PQ(sql);
return db.any(final_sql)
.then(function (data) {
pgp.end();
return 'successful';
})
.catch(function (error) {
console.log("Error: " + error);
pgp.end();
});
}
Request body
[{
"class_id":"1",
"timestamp_start":"2017-11-14 14:01:23.634437+00",
"timestamp_end":"2017-11-14 15:20:23.634437+00"
}, {
"class_id":"2",
"timestamp_start":"2017-11-14 15:01:23.634437+00",
"timestamp_end": "2017-11-14 16:20:23.634437+00"
}]
When I run api in postman, I get the error is:
column "timestamp_start" is of type timestamp with time zone but
expression is of type text
Issue is obviously from ARRAY of string that I used in sql, my question is how to create ARRAY of timestamp for UNNEST, or any suggestion are appreciated.
Thanks
Never initialize the database inside the handler, see: Where should I initialize pg-promise
Never call pgp-end() inside HTTP handlers, it destroys all connection pools.
Use static ColumnSet type to generate multi-insert queries.
Do not return from db.any, there is no point in that context
You must provide an HTTP response within an HTTP handler
You are providing a confusing semantics for column class_id. Why is it called like that and yet being converted into a timestamp?
Never concatenate objects with strings directly.
Never concatenate SQL strings manually, it will break formatting and open your code to SQL injection.
Use Database methods according to the expected result, i.e. none in your case, and not any. See: https://github.com/vitaly-t/pg-promise#methods
Initialize everything needed only once:
const db = pgp(/*connection*/);
const cs = new pgp.helpers.ColumnSet([
'class_id',
{
name: 'timestamp_start',
cast: 'timestamp'
},
{
name: 'timestamp_end',
cast: 'timestamp'
}
], {table: {table: 'class', schema: 'sa1'}});
Implement the handler:
api.post(PREFIX + '/class/insert', request => {
const sql = pgp.helpers.insert(request.body, cs);
db.none(sql)
.then(data => {
// provide an HTTP response here
})
.catch(error => {
console.log('Error:', error);
// provide an HTTP response here
});
}
Many thanks to #JustMe,
It worked after casting array
var sql =
"INSERT INTO sa1.class(class_id, timestamp_start, timestamp_end) " +
"VALUES( "+
"UNNEST(ARRAY" + JSON.stringify(classes).replace(/"/g, "'") + "), " +
"UNNEST(ARRAY" + JSON.stringify(starts).replace(/"/g, "'") + "::timestamp[]), " +
"UNNEST(ARRAY" + JSON.stringify(ends).replace(/"/g, "'") + "::timestamp[])"
The legacy system used to store passwords in query's output format,
SELECT
HASHBYTES('SHA1', CONVERT(VARCHAR, HASHBYTES('SHA1', CONVERT(NVARCHAR(4000), ’test'))) + 'mysalt')
where the password is test and mysalt is the salt used.
The result is something like
0x169A0EF01AA369518D6810E14872A3A003A1F0AA
I have to take that encrypted password and create a node function to get the same result as the above query
Node.js is not going to replace a t-sql query. You would still use t-sql to query your database and something like the tedious module connection to the database. This is an example from https://msdn.microsoft.com/library/mt715784.aspx on how to connect from node.js to SQL Server and execute a query. Some modifications to the executeStatement function would get you going.
var Connection = require('tedious').Connection;
var config = {
userName: 'yourusername',
password: 'yourpassword',
server: 'yourserver.database.windows.net',
// When you connect to Azure SQL Database, you need these next options.
options: {encrypt: true, database: 'AdventureWorks'}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
executeStatement();
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
function executeStatement() {
request = new Request("SELECT c.CustomerID, c.CompanyName,COUNT(soh.SalesOrderID) AS OrderCount FROM SalesLT.Customer AS c LEFT OUTER JOIN SalesLT.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID GROUP BY c.CustomerID, c.CompanyName ORDER BY OrderCount DESC;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
> Am trying to provide login credentials with email and password using postgres database table.
postgres database tables. When i get records it should send 200 status
to my page.Am getting error on query. Kindly help me out how to use
select with where condition. Am missing some syntax.
getUser : function(req, res) {
var pg = require('pg');
var conString = process.env.DATABASE_URL || "postgres://test:test#localhost:5432/wallet";
var client = new pg.Client(conString);
client.connect();
console.log(req.query.email_id);
console.log(req.query.user_password);
var query = client.query("select * from pp_user_profile where email_id ="+req.query.email_id+ "and" + "user_password=" +req.query.password);
query.on("end", function (result) {
client.end();
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Success');
res.end();
});
},
Try the below syntax:
"select * from pp_user_profile where email_id = '"+req.query.email_id+"' and user_password= '"+req.query.password+"'";
I have a social app for which I am trying to create a friend activities feed using Azure Sql Server.
I have 3 tables I want to select from:
Songs
-createdAt
-id
-userId
-trackName
-etc
Comments
-createdAt
-id
-userId
-songId
-text
Likes
-createdAt
-id
-userId
-songId
I have the users that the current user is following stored in an array named 'follows'.
How do I go about selecting the 40 most recent items from those 3 tables where userId in each table is in the follows array?
Edit:
function getActivities(userId) {
var deferred = Q.defer();
var follows = [];
getFollowing(userId).then(function (results) {
follows.push(userId);
_.each(results, function (user) {
follows.push(user.toUserId);
});
return;
}).then(function () {
var stringified = "'" + follows.join("','") + "'";
var queryString = "SELECT * FROM comments, songs, likes WHERE comments.userId IN (" + stringified + ") OR songs.userId IN (" + stringified +") OR likes.userId IN (" + stringified + ")";
var params = [];
return sqlQuery(queryString, params);
}).then(function (results) {
console.log('Activities: ', results);
deferred.resolve(results);
}, function (error) {
console.log('Error: ', error.message);
deferred.reject(error.message);
});
return deferred.promise;
}
Alright, so I dug into JOINS a little more and realized how easy it actually is once you wrap your head around it. Here is what I did to complete this:
var queryString = "SELECT TOP 50 follows.id AS followId, follows.toUserId AS followToUserId, follows.fromUserId AS followFromUserId, comments.text AS commentText, profiles.userId, profiles.username, profiles.name, profiles.profileImage, songs.trackId, songs.trackName, songs.artistName, songs.collectionName, songs.artworkUrl100, songs.caption, songs.id AS songId, activities.id AS activityId, activities.type AS activityType, activities.objectId AS activityObjectId, activities.parentType AS activityParentType, activities.parentId AS activityParentId, activities.__createdAt AS activityCreatedAt FROM activities ";
queryString += "INNER JOIN profiles ON (profiles.userId = activities.userId) ";
queryString += "LEFT JOIN songs ON (songs.id = activities.objectId AND activities.type = 'songs') OR (songs.id = activities.parentId AND activities.parentType = 'songs') ";
queryString += "LEFT JOIN comments ON (activities.type = 'comments' AND comments.id = activities.objectId) ";
queryString += "LEFT JOIN follows ON (activities.type = 'followed' AND activities.userid = follows.fromUserId) ";
queryString += "WHERE activities.userId IN (SELECT follows.toUserId AS userId FROM follows WHERE follows.fromUserId = ? AND follows.isFollowed = 'true') ";
queryString += "ORDER BY activities.__createdAt DESC";
var params = [userId];
mssql.query(queryString, params, {
success: function (results) {
_.each(results, function (result) {
//Remove columns with null or undefined values
for (var i in result) {
if (result[i] === null || result[i] === undefined) {
delete result[i];
}
}
});
response.send(200, results);
},
error: function (error) {
response.send(400, error.message);
}
});