How can I access column's from SELECT, in my WHERE statement? I'm probably missing quotes. For context, this is in a controller, in Strapi CMS, which runs on a node.js server.
Problem:
Occurs at AND statement (mainly the first st_geomfromtext line):
const rawBuilder = strapi.connections.default.raw(
`
SELECT
locations.id as Location_ID,
locations.Title as Location_Title,
locations.Latitude as Location_Latitude,
locations.Longitude as Location_Longitude,
things.id,
things.Title,
things.Location
FROM locations
RIGHT JOIN things
ON locations.id = things.Location
WHERE things.Style = ` + ctx.query['Style.id'] + `
AND round(st_distance_sphere(
st_geomfromtext(CONCAT('POINT(',locations.Longitude, ' ', locations.Latitude,')')),
st_geomfromtext(CONCAT('POINT(` + ctx.query.Longitude + ` ` + ctx.query.Latitude + `)'))
)) <= ` + 5000
)
Test works:
Just for fun, same as above, but just passed request variables for both st_geomfromtext lines, and the response works; no SQL error:
AND round(st_distance_sphere(
st_geomfromtext(CONCAT('POINT(` + ctx.query.Longitude1 + ` ` + ctx.query.Latitude1 + `)')),
st_geomfromtext(CONCAT('POINT(` + ctx.query.Longitude2 + ` ` + ctx.query.Latitude2 + `)'))
)) <= ` + 5000
So as far as I can tell, the first st_geomfromtext line is the culprit, however it (the 1st line) works fine in a Go server... another clue that this is just a syntax problem.
Below is a working example in SQL Server that should help you resolve this.
Please try these steps:
Remove the "AND" statement from your where clause and save it somewhere
Add some filter criteria that will give you just few known locations
Add new output fields in your select criteria for each function so you will know what you are comparing.
Select CONCAT('POINT(',locations.Longitude, ' ', locations.Latitude,')') from locations
Select st_geomfromtext(CONCAT('POINT(',locations.Longitude, ' ', locations.Latitude,')')) from locations
Note: the output to the geo functions this will probably look cryptic like 0xE6100000010C75931804564253C042CF66D5E7724340
Once the values line up the way you expect then add a new version of the where clause with the adjustments you have made.
Check the precision of the st_distance_sphere function. In SQL Server this is defaulted to meters.
Example in SQL Server
CREATE TABLE #locations (id INT, Title VARCHAR(50), Latitude DECIMAL(10,4), Longitude DECIMAL(10,4))
CREATE TABLE #things (id INT, Title VARCHAR(50), LocationId INT)
INSERT INTO #locations (id, Title, Latitude, Longitude) Values (1,'WH', 38.8977, -77.0365)
INSERT INTO #locations (id, Title, Latitude, Longitude) Values (2,'CB', 38.8899, -77.0091)
INSERT INTO #things (id, Title, LocationId) Values (100,'White House',1)
INSERT INTO #things (id, Title, LocationId) Values (101,'United States Capitol',2)
--My Location at the Washington Monument
DECLARE #myLat DECIMAL(10,4) = 38.8895;
DECLARE #myLong DECIMAL(10,4) = -77.0353
SELECT
loc.id as Location_ID,
loc.Title as Location_Title,
loc.Latitude as Location_Latitude,
loc.Longitude as Location_Longitude,
th.id,
th.Title,
th.LocationId,
geometry::STGeomFromText(CONCAT('POINT(',loc.Longitude, ' ', loc.Latitude,')'),4326) as ItemPoint,
geometry::STGeomFromText(CONCAT('POINT(',#myLat,' ',#myLong,')'),4326) as MyPoint,
geometry::STGeomFromText(CONCAT('POINT(',loc.Longitude, ' ', loc.Latitude,')'),4326).STDistance(geometry::STGeomFromText(CONCAT('POINT(',#myLat,' ',#myLong,')'),4326))
FROM #locations loc
RIGHT JOIN #things th ON loc.id = th.LocationId
DROP TABLE #locations
DROP TABLE #things
Related
I'm building a backend for my food application, and I need to create columns in food table and INSERT rows in nutrients table. I'm constructing a query, there are ~60 nutrients in every food, and there are hundreds of different nutrient types.
I used one of answers from MySQL: ALTER TABLE if column not exists as my template
for (let i = 0; i < food.nutrients.length; i++) {
createColumnsString += `
DROP PROCEDURE IF EXISTS \`create_column\`;
DELIMITER //
CREATE PROCEDURE \`create_column\`()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
ALTER TABLE \`food\` ADD COLUMN \`${food.nutrients[i].nutrientNumber}\` VARCHAR(45);
INSERT INTO \`nutrients\` (nutrientid, nutrientname, unit) VALUES ("${food.nutrients[i].nutrientNumber}", "${food.nutrients[i].nutrientName}", "${food.nutrients[i].unitName}");
END //
DELIMITER ;
CALL \`create_column\`();
DROP PROCEDURE \`create_column\`; `;
}
console.log(createColumnsString);
db.query(createColumnsString);
the console.log(createColumnsString) for each nutrient prints this in Node console:
DROP PROCEDURE IF EXISTS `create_column`;
DELIMITER //
CREATE PROCEDURE `create_column`()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
ALTER TABLE `food` ADD COLUMN `269.3` VARCHAR(45);
INSERT INTO `nutrients` (nutrientid, nutrientname, unit) VALUES ("269.3", "Sugars, Total NLEA", "G");
END //
DELIMITER ;
CALL `create_column`();
DROP PROCEDURE `create_column`;
And it works when i paste it to MySQL Workbench. I can put all ~60 queries one after another and it does what it's supposed to do.
On the other hand, db.query(createColumnsString) gives me this:
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 'DELIMITER //\n" +
'CREATE PROCEDURE `create_column`()\n' +
'BEGIN\n' +
"DECLARE CONTINUE HANDLER F' at line 1",
sqlState: '42000',
index: 1,
sql: '\n' +
'DROP PROCEDURE IF EXISTS `create_column`; \n' +
'DELIMITER //\n' +
'CREATE PROCEDURE `create_column`()\n' +
'BEGIN\n' +
'DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;\n' +
'ALTER TABLE `food` ADD COLUMN `303` VARCHAR(45); \n' +
'INSERT INTO `nutrients` (nutrientid, nutrientname, unit) VALUES ("303", "Iron, Fe", "MG"); \n' +
'END // \n' +
'DELIMITER ; \n' +
'CALL `create_column`(); \n' +
'DROP PROCEDURE `create_column`; \n' +
'DROP PROCEDURE IF EXISTS `create_column`; \n' +
I'm using mysql library for connection. Does it even permit the use of DELIMITER? What am I doing wrong?
Create a Food table to contain the food info.
id int
name varchar(30)
... etc etc
Create a Nutriets table to hold nutrient info.
id int
nutrientname varchar(30)
unit _not sure of type_
. . . etc etc
Then as many foods will have the same nutrients in them you need a xref table, or link table to connect them
That table is simply something like this
food_nutrients table
id int
food_id int
nutrient_id int
Nowyou can link any food to any nutrient, all you need is either the id of the food or the id of the nutrient to be able to list all a foods nutrients, or all the food that contain any nutrient.
Need to return an array that has data from table containing the list of Product IDs, unit price and quantity of the user's transaction. Formatted as follows:
[{
'id':'#productID1#',
'price':'#productPrice1#',
'quantity':'#productQty1#'
},
{
'id':'#productID2#',
'price':'#productPrice2#',
'quantity':'#productQty2#'
}]
Tried to use quotation marks to add titles (product, price & quantity) as needed as well as apostrophes. However, I am receiving a \ wherever I have apostrophes and am not able to get the desired formatting towards the beginning and end of the variable. Here is what I am outputting:
'id\':\'WE119017\',\'price\':\'undefined\',\'quantity\':\'undefined,
id\':\'WE119012\',\'price\':\'undefined\',\'quantity\':\'undefined,
id\':\'858191\',\'price\':\'undefined\',\'quantity\':\'undefined,
id\':\'WE108003\',\'price\':\'undefined\',\'quantity\':\'undefined,
id\':\'854220\',\'price\':\'undefined\',\'quantity\':\'undefined'
Any help would be appreciated as I have no Javascript knowledge or experience and am trying to use online resources to try to figure this out. Thanks!
function() {
var products = {{Ecommerce Imp Object}};
return products.reduce(function(arr, prod)
{ return arr.concat("id':'" + prod.id + "'," + "'price':'" + prod.price + "'," + "'quantity'"+":'" + prod.quantity); }, []).join(',');
}
I'm trying to insert values using mysql in nodejs. I had written the following code and installed MySQL support via npm,But canot to INSERT INTO the table due to this problem.
My code;
var mysql = require('mysql');
var values=randomValueHex(8);
var sql = "INSERT INTO `activationkeys`(`activationKey`, `productId`)
VALUES ( values ,'3')";
con.query(sql, function (err, result) {
if (err) throw err;
console.log("1 record inserted");
});
My Error on terminal:
Error: ER_PARSE_ERROR: 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 ''3')'
How can i solve this problem?
Why are you using back quote for the column names? We do not need that in column names. You can simply create your dynamic sql query by using + operator on the column values like this:
var sql = "INSERT INTO activationkeys (activationKey, productId) VALUES ( " + values + " ,'3')";
Instead of
var sql = "INSERT INTO `activationkeys`(`activationKey`, `productId`)
VALUES ( values ,'3')";
Please try this
var sql = "INSERT INTO `activationkeys`(`activationKey`, `productId`)
VALUES ( " + values + " ,'3')";
provided values is a string
values currently means nothing the way you're using it in the SQL query.
What is values? Is it an integer, or a string?
Nevertheless, you need to concatenate the values variable within the string.
var sql = "INSERT INTO `activationkeys`(`activationKey`, `productId`) VALUES (" + values + ",'3')";
And one more correction values variable have to give like this '" + values + "' . This is the most correct way of define as a variables. Otherwise you give like this " + values + " , you may be have an error accure like this Error: ER_BAD_FIELD_ERROR: Unknown column 'xxxxxx' in 'field list'. And my code is
var sql = "INSERT INTO `activationkeys`(`activationKey`, `productId`) VALUES ( '" + values + "' , 3 )";
This is simple way to write SQL query in you JavaScript code.
Try It Once
const QUERY = INSERT INTO users (firstName, lastName) VALUES ( "${firstName}", "${lastName}")
Note: Please wrap your complete query into the back ticks.
so most of my coding is done however as some variables cannot be provided (undefined jQuery results)
the layout of the concatenation string will need to be dynamic and not static
eg. if there is no street number it should pass that variable and continue, and not insert the line breaks.
Current code (added commas to assist with Result explanation):
document.getElementById('fulla').value= streetNumber + ",\n" + streetName + ",\n" + suburb + ",\n" + city + ",\n" + state + ",\n" + country + ",\n" + zip;
Result:
null,<br>
Unnamed Road,<br>
Mabeskraal,<br>
null,<br>
North West,<br>
South Africa,<br>
0313<br>
So what I want it to do is just provide me with the rest without the null Value:
Unnamed Road,<br>
Mabeskraal,<br>
North West,<br>
South Africa,<br>
0313
Get a little more control and save some repetition by stuffing everything into an array:
var addrLines = [streetNumber, streetName, suburb, city, state, country, zip];
filtering away the nulls:
addrLines = addrLines.filter(function(line){return line!=null});
and joining what's left
var addr = addrLines.join("\n");
I am using postgresql 9.3 in my node.js application. In my database i have some 7lakhs records now. Also in my database i have json datatype column.
My query is as following:
EXPLAIN ANALYSE select id_0, name_0, id_1, name_1, id_2, name_2, id_3, name_3, id_4, name_4, latitude, longitude, to_char(collecteddate, 'dd/mm/yyyy') as collecteddate, key, value->>'xxxxx' as value from table where
CAST(value->'xxxxx'->> 'aaaaa' as INTEGER)BETWEEN 1 and 43722 and value->'PCA_2011'->> 'aaaaa' NOT LIKE ' ' and
CAST(value->'xxxxx'->> 'bbbbb' as INTEGER)BETWEEN 1 and 100 and value->'xxxx'->> 'bbbbb' NOT LIKE ' '
and leveltype = 'nnnn' and id_1= 'ww' and id_0 = 'uuu' and collecteddate = '2011-03-31';
This query will retrieve almost 1lakh records and takes 3 secs to be executed. I have created index for the json column and also the columns in where conditions. But i think its very long time to execute. Is there any way to reduce the execution time. I am new to this database optimization concepts, is there any optimization techniques to reduce my execution time to some milli seconds. Thanks in advance..
EDIT:
My index definition:
CREATE INDEX index_pop on table (id_0, id_1, collecteddate, leveltype, key, (value->'xxxxx'->>'aaaa'));
My Explain analyses result:
"Bitmap Heap Scan on table (cost=1708.27..59956.46 rows=1 width=132) (actual time=880.576..5137.266 rows=93615 loops=1)"
" Recheck Cond: (((id_0)::text = '356'::text) AND ((id_1)::text = '9'::text) AND (collecteddate = '2011-03-31'::date) AND ((leveltype)::text = 'pppp'::text))"
" Filter: ((((value -> 'xxxx'::text) ->> 'aaaa'::text) !~~ ' '::text) AND (((value -> 'xxxxx'::text) ->> 'bbbb'::text) !~~ ' '::text) AND ((((value -> 'xxxxx'::text) ->> 'aaaaa'::text))::integer >= 1) AND ((((value -> 'PCA (...)"
" Rows Removed by Filter: 4199"
" -> Bitmap Index Scan on index_name (cost=0.00..1708.27 rows=37856 width=0) (actual time=828.856..828.856 rows=97814 loops=1)"
" Index Cond: (((id_0)::text = '356'::text) AND ((id_1)::text = '9'::text) AND (collecteddate = '2011-03-31'::date) AND ((leveltype)::text = 'ppppp'::text))"
"Total runtime: 5211.271 ms"
ALso 1 more thing: Bitmap Index Scan on index_name is different index other than in my where condition index, also y only 1 index is earched??