i want to use parameters for my dynamic queries. I have a statements like so:
RETURN QUERY EXECUTE 'SELECT * FROM boards AS b WHERE b.slug = $1 AND $2'
USING filter_slug, parent_id_query;
I get a ERROR: argument of AND must be type boolean, not type text
if i do it like this:
RETURN QUERY EXECUTE 'SELECT * FROM boards AS b WHERE b.slug = ''' || filter_slug || ''' AND ' || parent_id_query;
it works though.
I feel like i am missing something / not understanding something. Please help.
What you are missing is how parameters are used. Parameters are not macros that replace arbitrary text inside a SQL statement. Instead, they are literal values assigned to "variables" inside the code. These values are typically numbers, strings, or dates.
In particular, parameters cannot be used for:
identifiers (columns names and table names)
function names
operators
SQL keywords
general expressions
So, unfortunately, you have to construct that part of the query without a generic parameter (although you can have $2 = $3)
Related
I am looking for a function which can help me to query multiple input values on a particular column which stored as an array
Already tried using like function to search in a string
select *
from express_dwh.kengic_bag_seal_ad_json
where Sorter_id='KENGIC_1' and ad >='2019-08-21-0' and
wbns LIKE '%3008127238325%' OR wbns LIKE '%3008127259896%' OR wbns LIKE '%3008127263750%'
Error running query:
SYNTAX_ERROR: line 3:56: Left side of LIKE expression must evaluate to a varchar (actual: array(varchar))
You might be looking for the “overlaps” operator &&:
wbns && ARRAY[3008127238325,3008127259896,3008127263750]
Depending on the data type, you may need a cast like
wbns && ARRAY[3008127238325,3008127259896,3008127263750]::numeric[]
I have a table 'article' with column 'content' .I want to query Postgresql in order to search for a string contained in variable 'temp'.This query works fine-
pool.query("select * from article where upper(content) like upper('%some_value%')");
But when I use placeholder $1 and [temp] in place of some_value , I get the above error -
pool.query("select * from article where upper(content) LIKE upper('%$1%')",[temp] );
Note - Here $1 is a placeholder and should be replaced by the value in [temp] , but it treats '%$1%' as a string , I guess. Without the quotes ' ' , the LIKE operator doesn't work. I have also tried the query -
pool.query("select * from article where upper(content) LIKE upper(concat('%',$1,'%'))",[temp] );
to ensure $1 is not treated as a string literal but it gives the error -
error: could not determine data type of parameter $1
pool.query(
"select * from article where upper(content) LIKE upper('%' || $1 || '%')",
[temp]
).then( res => {console.log(res)}, err => {console.error(err)})
This works for me. I just looked at this Postgres doc page to try and understand what concat was doing to the parameter notation. Can't say that I understand the difference between using || operators and using concat string function at this time.
The easiest way I found to do this is like the following:
// You can remove [0] from character[0] if you want the complete value of character.
database.query(`
SELECT * FROM users
WHERE LOWER(users.name) LIKE LOWER($1)
ORDER BY users.id ASC`,
["%" + character[0] + "%"]
);
// [%${character}%] string literal alternative to the last line in the function call.
There are several things going on here, so let me break each line it down.
SELECT * FROM users
This is selecting all the columns associated with table users
WHERE LOWER(users.name) LIKE $1
This is filtering out all the results from the first line so that where the name(lowercased) column of the users table is like the parameter $1.
ORDER BY users.id ASC
This is optional, but I like to include it because I want the data returned to me to be in ascending order (that is from 0 to infinity, or starting low and going high) based on the users.id or the id column of the users table. A popular alternative for client-side data presentation is users.created_at DESC which shows the latest user (or more than likely an article/post/comment) by its creation date in reverse order so you get the newest content at the top of the array to loop through and display on the client-side.
["%" + character + "%"]
This part is the second argument in the .query method call from the database object (or client if you kept with that name, you can name it what you want, and database to me makes for more a sensical read than "client", but that is just my personal opinion, and it's highly possible that "client" may be the more technically correct term to use).
The second argument needs to be an array of values. It takes the place of the parameters inserted in the query string, for example, $1 or ? are examples of parameter placeholders which are filled in with a value in the 2nd argument's array of values. In this case, I used JavaScript's built-in string concatenation to provide a "includes" like pattern, or in plain-broken English, "find me columns that contain a 'this' value" where name(lowercased) is the column and character is the parameter variable value. I am pulling in the parameter value for the character variable from req.params (the URL, so http://localhost:3000/users/startsWith/t), so combining that with % on both ends of the parameter, it returns me all the values that contain the letter t since is the first (and only) character here in the URL.
I know this is a VERY late response, but I wanted to respond with a more thorough answer in case anyone else needed it broken down further.
In my case :
My variable was $1, instead of ?1 ...
I was customizing my query with #Query
I'm using PostgreSQL 9.2.10
Suppose you have 2 PostgreSQL functions, 'called_function' and 'caller_function', second one is calling the first one. Exactly:
CREATE FUNCTION called_function () RETURNS varchar AS
$BODY$
BEGIN
RETURN 'something';
END;
CREATE FUNCTION caller_function () RETURNS varchar AS
$BODY$
BEGIN
RETURN called_function ();
END;
Now, using SQL and knowing only function name, I would like to find out if 'caller_function' calls some other function. Or if 'called_function' is called by some other function. Is it possible?
I tried to get function's OID (let's say it is '123') and then I looked into pg_depend table:
SELECT * FROM pg_catalog.pg_depend dep WHERE dep.objid = 123 OR dep.objsubid = 123 OR dep.refobjid = 123 OR dep.refobjsubid = 123 OR dep.refobjsubid = 123;
But it finds only pg_language and pg_namespace dependency. Nothing more.
I had same problem to define a function and because of dependency It didn't work. Then I solved my problem with adding this command before the commands
SET check_function_bodies = false;
hope to help someone else
Look at the table pg_proc for example :
select nspname,proname,prosrc from pg_proc join pg_namespace nsp on (pronamespace=nsp.oid) where prosrc like '%called_function%'
Impossible in the general case; but a limited (restricted-domain) solution is perfectly doable --- and might prove adequate for your needs.
(The Most Obvious of the Many) Limitations
Fails (false negative) if name of callee (a function to be invoked) is specified as a quoted identifier.
Fails (false negative) if name of callee is passed as argument.
Fails (false negative) if name of callee is read from a relation at runtime.
Fails (false negative) if name of callee is assembled from tokens.
Fails (false positive) if name of callee is present just as literal.
Fails (false positive) if name of callee is present in a multi-line comment.
Does not account for function overloading.
Does not account for functions invoked via triggers.
Does not account for functions invoked per query-rewrite rules.
Does not account for effects of query rewriting rules.
Knows nothing about functions written in non-interpreted PLs like C.
Sample Output
Your routine... | ...calls these routines:
---------------------------------+-------------------------------------------------
create_silo_indexes | {get_config__f_l__ea_silo,subst_silo_id}
demux__id_creat_thread | {}
grow__sensor_thhourly | {containing_hhour_t_begin}
SQL
WITH routine_names AS (
SELECT DISTINCT(Lower(proname)) AS name --#0
FROM pg_proc
WHERE proowner = To_Regrole(current_role)
)
SELECT
name AS "Your routine...",
Array_Remove( --#8
Array( --#7
SELECT Unnest( --#5
String_To_Array( --#4
Regexp_Replace( --#3
Regexp_Replace( --#2
Lower(PG_Get_Functiondef(To_Regproc(name))) --#1
, '--.*?\n', '', 'g'
)
, '\W+', ' ', 'g'
)
, ' '
)
)
INTERSECT --#6
SELECT name FROM routine_names
ORDER BY 1
)
, name
) AS "...calls these routines:"
FROM
routine_names;
How It Works
#0 Collect names of all the routines which could be callers and/or callees. We cannot handle overloaded functions correctly anyway, so just DISTINCT to save trouble later on; SQL is case-insensitive apart from quoted identifiers which we are not bothering with anyway, so we just Lower() to simplify comparison later.
#1 PG_Get_Functiondef() fetches complete text of the CREATE FUNCTION or CREATE PROCEDURE command. Again, Lower().
#2 Strip single-line comments. Note the lazy (non-greedy) *? quantifier: the usual * quantifier, if used here, would remove the first single-line comment plus all subsequent lines!
#3 Replace all characters other than letters and digits and _, with a space. Note the + quantifier: it ensures that 2+ contiguous removed characters are replaced by just 1 space.
#4 Split by spaces into an array; this array contains bits of SQL syntax, literals, numbers, and identifiers including routine names.
#5 Unnest the array into a rowset.
#6 INTERSECT with routine names; result will consist of routine names only.
#7 Convert rowset into an array.
#8 Since input was complete text of a CREATE FUNCTION f ... command, extracted routine names will obviously contain f itself; so we remove it with Array_Remove().
(SQL tested with PostgreSQL 12.1)
In my report query I have a where clause that needs to be replaced dynamically based on the data chosen in the front end.
The query is something like :
where ?=?
I already have a code to replace the value - I created report parameter and linked to the value ? in the query.
Example:
where name=?
Any value of name that comes from front end replaces the ? in the where clause - this works fine.
But now I need to replace the entire clause (where ?=?). Should I create two parameters and link them to both the '?' ?
No, unfortunately most database engines do not allow to use a query parameter for handling a dynamic column name. This is for security considerations.
So you need to keep an arbitrary column name in the query:
where name=?
And then in "beforeOpen" script of the dataset replace 'name' with a report parameter value:
this.queryText=this.queryText.replace("name",params["myparameter"].value);
To prevent SQLIA i recommend to test the value of the parameter in this script. There are many ways to do this but a white list is the strongest test, for example:
var column=params["myparameter"].value;
if (column=="name" || column=="id" || column=="account" || column=="mycolumnname"){
this.queryText=this.queryText.replace("name",column);
}
In addition to Dominique's answer and your comment, then you'll just need a slightly more advanced logic.
For example, you could name your dynamic column-name-value pairs (column1, value1), (column2, value2) and so on. In the static text of the query, make sure to have bind variables for value1, value2 and so on (for example, with Oracle SQL, using the syntax
with params as (
select :value1 as value1,
:value2 as value2 ...
from dual
)
select ...
from params, my_table
where 1=1
and ... static conditions....
Then, in the beforeOpen script, append conditions to the query text in a loop as needed (the loop left as an exercise to the reader, and don't forget checking the column names for security reasons!):
this.queryText += " and " + column_name[i] + "= params.value" + i;
This way you can still use bind variables for the comparison values.
I am using the LIST function to create a ';' delimited list of values. The type is numeric (19,2). For some reason the precision appears to be ignored when using the list function. When performing a simple select on this column the values look good, ie "12.00". However, if I use a LIST() my results are of format "12.000000"
This is my LIST usage:
LIST(case when tblWOService.PricePerVehicle is null then ' ' else CONVERT(decimal(19,2),tblWOService.PricePerVehicle end,';')
The CONVERT does not change the result. Any ideas?
Thanks!
Have you tried explicitly converting your empty string?
LIST(
case when tblWOService.PricePerVehicle is null then CONVERT(decimal(19,2),' ')
else CONVERT(decimal(19,2),tblWOService.PricePerVehicle) end,';'
)
I've run into a similar datatype issue with CASE statements in T-SQL.