I need to add a condition inside prepared statement in postgres.
Pseudocode (doesn't works, fires an error "argument of WHERE must be type boolean, not type text"):
if (nameFilter) {
whereParam = `name LIKE %${nameFilter}%`
} else {
whereParam = "true"
}
let query = prepare("SELECT * FROM users WHERE $1", whereParam);
Pseudocode (works but looks ugly):
if (nameFilter) {
likeParam = `%${nameFilter}%`
} else {
likeParam = "%"
}
let query = prepare("SELECT * FROM users WHERE name LIKE $1", likeParam);
For some reasons(query is really complex with a bunch of AND) manipulations with a string is not an option, so this will not help
if (nameFilter) {
q = `SELECT * FROM users WHERE name LIKE $1`
} else {
q = "SELECT * FROM users"
}
let query = prepare(q, nameFilter);
Desirable to have statement similar to SELECT * FROM users WHERE $1 AND $2 AND $3 ...
Any suggestions?
This query will work for you.
select * from users where
case
when coalesce($1, '') = '' then true
else (name ~ $1)
end;
The only thing you can pass as a parameter is a constant; you cannot pass part of an SQL query like name LIKE '%pattern%'.
So if your query is really different every time, you have to construct the SQL string in your code, just like you say you cannot do "for some reasons".
It may be annoying, but there is no other way.
When you construct an SQL statement, make sure you never concatenate strings like this:
sql = "SELECT * FROM users WHERE username ='" + username + "'"
because that would be vulnerable to SQL injection.
Related
I am trying to build a sql statement dynamically and this is one variation of the result.
sqlQuery {
name: 'fetch-products',
text: 'select * from products where category =
$1 and designer in $2',
values: [ 'WOMENSCLOTHING', "('Adjavon', 'ALC', 'Adele', 'Bagley')" ]
}
I build the sql with the following code segment:
const {
category,
designers,
} = JSON.parse(filters);
let values = [category];
let text = 'select * from products where category = $1';
if(designers) {
text = text + ' and designer in $2';
values.push(designers);
}
I execute it in the following segment:
try {
const allProducts = await pool.query(sqlQuery);
res.status(200).json(allProducts.rows);
} catch (error) {
console.error(error);
return res.status(500).send('Problems gettting products by category.')
}
And get the following error:
error: syntax error at or near "$2"
I am thinking the error may be the double quotes placed around designer when it is pushed on the values array:
values: [ 'WOMENSCLOTHING', "('Adjavon', 'ALC', 'Adele', 'Bagley')" ]
I don't know what library you are using exactly, but the values property looks highly suspicious.
sqlQuery {
name: 'fetch-products',
text: 'select * from products where category =
$1 and designer in $2',
values: [ 'WOMENSCLOTHING', "('Adjavon', 'ALC', 'Adele', 'Bagley')" ]
}
If your drivr/library supports this, the second element in the array should be an actual array and not a string like '("foo", "bat")'. How is the driver supposed to know this is meant as a list and not a single string that has this value?
I guess in a nutshell you have to bring the query in this form:
const query = 'select * from products where category = $1 and designer in ($2, $3, $4, $5)'
const values = [ 'WOMENSCLOTHING', 'Adjavon', 'ALC', 'Adele', 'Bagley' ]
That requires some extra work on the backend to map the values and bring them into the right shape.
I guess you could get that done with something like this:
const category = 'icecream'
const designers = ['jim', 'maria']
let values = [category];
let text = 'select * from products where category = $1';
if (designers) {
text += ` and designer in (${designers.map((d, i) => `$${i+2}`).join(', ')})`;
values = [...values, ...designers];
}
console.log(text);
console.log(values);
I'm using the postgres crate which makes a query with postgres::Connection. I query a table based on a string value in an ilike '%search_string%' expression:
extern crate postgres;
use std::error::Error;
//DB Create queries
/*
CREATE TABLE TestTable (
Id SERIAL primary key,
_Text varchar(50000) NOT NULL
);
insert into TestTable (_Text) values ('test1');
insert into TestTable (_Text) values ('test1');
*/
fn main() -> Result<(), Box<dyn Error>> {
let conn = postgres::Connection::connect(
"postgres://postgres:postgres#localhost:5432/notes_server",
postgres::TlsMode::None,
)?;
let text = "test";
// //Does not work
// let query = &conn.query(
// "
// select * from TestTable where _text ilike '%$1%'
// ",
// &[&text],
// )?;
//Works fine
let query = &conn.query(
"
select * from TestTable where Id = $1
",
&[&1],
)?;
println!("Rows returned: {}", query.iter().count());
Ok(())
}
If I uncomment the //Does not work part of the code, I will get the following error:
thread 'main' panicked at 'expected 0 parameters but got 1'
It appears it doesn't recognize the $1 parameter that is contained in the ilike expression. I've tried escaping the single quotes and that doesn't change it.
The only dependencies are:
postgres = { version = "0.15.2", features = ["with-chrono"] }
To my surprise, here was the fix:
let text = "%test%";
let query = &conn.query(
"
select * from TestTable where _text like $1
",&[&text],
)?;
Apparently the postgres function knows to add single quotes around strings in this scenario.
I found out about this from here: https://www.reddit.com/r/rust/comments/8ltad7/horrible_quote_escaping_conundrum_any_ideas_on/
An example should do the magic.
At the top, I am using pg. So, import it. My code looks like
const title = req.params.title;
const posts = await db.query("SELECT * FROM postsTable INNER JOIN usersTable ON postsTable.author = usersTable.username WHERE title ILIKE $1 ORDER BY postsTable.created_on DESC LIMIT 5;", [`%${title}℅`])
i created domain in postgres:
create domain arrayofids as numeric[];
Now i want to use the domain in spring data like this:
String fakeQuery = "unnest(CAST (:ids AS arrayofids))";
Query nativeQuery = entityManager.createNativeQuery(fakeQuery);
BigInteger[] arrayOfids = new BigInteger[] {new BigInteger("1"),new BigInteger("2)} //or It can be List. It is not important
nativeQuery.setParameter("ids", arrayOfids);
List resultList = nativeQuery.getResultList();
Of course i get Error:
org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to arrayofIds
Before i used https://dalesbred.org/docs/api/org/dalesbred/datatype/SqlArray.html and it worked fine or did custom types in JDBC myself. Hibernate doesn't allow use my domain easy.
Query like that:
select * from mtTbale where id in :ids
is not interested. I should use the domain with unnest and CAST
Make :ids as a text representation of an array of numbers, i.e. "{1, 2}" and add SELECT to the query.
Try this:
String fakeQuery = "SELECT unnest(CAST (:ids AS arrayofids))";
Query nativeQuery = entityManager.createNativeQuery(fakeQuery);
String arrayOfids = "{" + 1 + ", " + 2 + "}"; // obtain the string as is relevant in your case
nativeQuery.setParameter("ids", arrayOfids);
List resultList = nativeQuery.getResultList();
and the second query should look like this:
select * from mtTbale where id = ANY(CAST(:ids AS arrayofids));
You may also use Postgres shorthand (and more readable) cast syntax.
Instead of CAST(:ids AS arrayofids) use :ids::arrayofids.
I'm trying to use Sequelize to find all distinct fields in a column, using a query with a where clause. I've searched the Sequelize docs and tried a number of different things, but haven't yet found the correct syntax.
Here's my current draft syntax:
var searchResults = connectors.cars.findAll({
attributes: [
connectors.Sequelize.options.distinct
],
where: {
condition: connectors.Sequelize.where(connectors.Sequelize.fn('LOWER', connectors.Sequelize.col('mfgr')), 'LIKE', '%' + searchString + '%')
}
});
What is the correct way to use options.distinct alongside a where clause?
Note: edited to remove a bunch of extra code that had been requested in the comments, but which in retrospect may have been obfuscating the issue.
Really more of a comment, but what's going on with this code?
}).then((searchResults) => searchResults.map((item) => item.dataValues));
debugger;
return searchResults; <== ERROR IS THROWN HERE
1) What is the destination of the map()? 2) Won't the return occur before the results are returned, as it's not in the .then() block? Should it not be more like this:
}).then((searchResults) => {
var new_results = searchResults.map((item) => item.dataValues));
debugger;
return new_results;
}
Am I missing something?
I'm getting the impression that this is hard to do in raw sql, let alone Sequelize. I found an answer that uses raw sql here:
const myQuery = "WITH cte AS\n" +
"( SELECT id, mfgr, ROW_NUMBER() OVER (PARTITION BY mfgr ORDER BY mfgr DESC) AS rn\n" +
" FROM cars\n" +
" WHERE LOWER(mfgr) like '%" + searchString + "%'\n" +
")\n" +
"SELECT *\n" +
"FROM cte\n" +
"WHERE rn = 1";
let searchResults = connectors.db.query(myQuery);
I need to execute following query using phalcon framework:
"SELECT id FROM table GROUP BY id HAVING '31' = ALL(array_agg(status))"
How can I execute this query using phalcon?
When I do following:
Model::query()
->columns(['id'])
->groupBy('id')
->having('31 = ALL(array_agg(status))')
->execute();
I get this error message:
Syntax error, unexpected token ALL, near to '(array_agg(status)) ', when parsing: SELECT id FROM [SomeNameSpace\Model] GROUP BY [id] HAVING 31 = ALL(array_agg(status)) (137)
I'm not 100% sure which Postgres functions are supported, but you can try like this:
Model::query()
->columns([
'id',
'ALL(array_agg(status)) AS statusCounter'
])
->groupBy('id')
->having('31 = statusCounter')
->execute();
Notice that I moved the aggregation functions in the select, rather in having clause.
UPDATE: here is an example of very custom query. Most functions used are not supported and it's sometimes cleaner just to write a simple SQL query and bind the desired Model to it:
public static function findNearest($params = null)
{
// A raw SQL statement
$sql = '
SELECT *, 111.045 * DEGREES(ACOS(COS(RADIANS(:lat))
* COS(RADIANS(X(coords)))
* COS(RADIANS(Y(coords)) - RADIANS(:lng))
+ SIN(RADIANS(:lat))
* SIN(RADIANS(X(coords)))))
AS distance_in_km
FROM object_locations
ORDER BY distance_in_km ASC
LIMIT 0,5;
';
// Base model
$model = new ObjectLocations();
// Execute the query
return new \Phalcon\Mvc\Model\Resultset\Simple(
null,
$model,
$model->getReadConnection()->query($sql, $params)
);
}
// How to use:
\Models\ObjectLocations::findNearest([
'lat' => 42.4961756,
'lng' => 27.471543300000008
])
You need to add ALL as dialect extension. Check this topic for example https://forum.phalconphp.com/discussion/16363/where-yearcurrenttimestamp-how-to-do-this