Is it possible to do something along the lines of:
define name1 = '23'
select * from my_db where value1 like '%' + name1 + %'
You are close. Here's a working example.
Use the variable command to register your variable. Then exec, which is a plsql block, to assign the value. Lastly use it in the select as a bind variable. As noted use || for concat operations not +
SQL> var name1 varchar2(20)
SQL> exec :name1 := '23';
PL/SQL procedure successfully completed.
SQL> select * from my_db where value1 like '%' || :name1 || '%';
Using the with statement allows you to inject the constant into the query.
WITH
name1 AS
(
SELECT 23 VALUE FROM DUAL
)
SELECT *
FROM MY_DB
WHERE VALUE1 LIKE '%' || (SELECT VALUE FROM NAME1) || '%'
;
What problem are you trying to solve by moving the constant out of the query?
Related
I have a procedure that queries schema and table. I want this to not overwrite the variable instead append, because the result I want to create view.
DECLARE
rec record;
sqlPlaceholder text;
BEGIN
FOR rec IN SELECT table_schema, table_name
FROM information_schema.tables
LOOP
sqlPlaceholder := sqlPlaceholder || 'SELECT ogc_fid, wkb_geometry FROM ' ||
rec.table_schema || '.' || rec.table_name || ' UNION ';
END LOOP;
strSQL := 'SELECT * FROM (' || sqlPlaceholder || ')';
RAISE INFO 'sample output %' , strSQL;
The variable sqlPlaceholder only holds the last assignment from the loop. as it's overwritten by each loop.
I need to figure out how add them all in loop.
call create_view()
Value of string inside loop SELECT * FROM public._data_202101 UNION
Value of string inside loop SELECT * FROM public._data_202102 UNION
Value of string inside loop SELECT * FROM public._data_202103 UNION
Value of string inside loop SELECT * FROM public._data_202104 UNION
Value of string inside loop SELECT * FROM public._data_202105 UNION
Value of string inside loop SELECT * FROM public._data_202106 UNION
Value of string inside loop SELECT * FROM public._data_202107 UNION
Value of string inside loop SELECT * FROM public._data_202108 UNION
Value of string inside loop SELECT * FROM public._data_202109 UNION
Value of string inside loop SELECT * FROM public._data_202110 UNION
Value of string inside loop SELECT * FROM public._data_202111 UNION
Value of string inside loop SELECT * FROM public._data_202112 UNION
Value of string outside ==> create table public._data_all as (SELECT * FROM public._data_202112 union)
The core problem in your PL/pgSQL code is that sqlPlaceholder starts out as NULL. Read the manual here.
NULL || anything is always NULL. Initialize the variable with an empty string ('') instead to fix that:
DECLARE
sqlPlaceholder text := '';
...
There's more, but don't bother. Here is a superior set-based solution:
SELECT string_agg(format('SELECT ogc_fid, wkb_geometry FROM %I.%I', table_schema, table_name), E'\nUNION ')
FROM information_schema.tables;
Redshift is pretty limited, I don't think it has format(). So:
SELECT string_agg('SELECT ogc_fid, wkb_geometry FROM ' || quote_ident(table_schema) || '.' || quote_ident(table_name), '\nUNION ')
FROM information_schema.tables;
Produces something like:
SELECT ogc_fid, wkb_geometry FROM public.tbl1
UNION SELECT ogc_fid, wkb_geometry FROM public.tbl2
UNION SELECT ogc_fid, wkb_geometry FROM public.tbl3
...
You want to quote identifiers properly to defend against SQL injection in any case! See:
INSERT with dynamic table name in trigger function
quote_ident() does not add quotes to column name "first"
Also, you probably want some filter and UNION ALL instead of UNION.
Related:
Loop through like tables in a schema
Error when calling a plpgsql function
I am trying to run the below query in a stored procedure and its not working.
We tried to print the query using NOTICE and we saw E gets appended to the regex and thats the reason the query doesnt show any output.
Not working
select order,version from mytable
where substring(version from quote_literal('[0-9]+\.[0-9]{1}'))
IN ('6.2') and order= 'ABC';
But the same query if i run from pgadmin query tool, it works fine.
Working
select order,version from mytable
where substring(version from '[0-9]+\.[0-9]{1}')
IN ('6.2') and order= 'ABC';
My requirement is to form the reqex dynamically in the stored procedure. Please guide on how to achieve this.
Below is the line of code in my stored procedure,
sql_query = sql_query || ' AND substring(version from ' || quote_literal( '[0-9]+\.[0-9]{1}' ) || ') IN (' || quote_literal(compatibleVersions) || ')';
raise notice 'Value: %', sql_query;
EXECUTE sql_query INTO query_result ;
and from notice i am getting the below output,
AND substring(version from E'[0-9]+\\.[0-9]{1}') IN ('{6.2}')
My requirement is to make this regex work.
I narrowed down to this query,
working
select substring(version from '[0-9]+\.[0-9]{1}') from mytable ;
not working
select substring(version from quote_literal('[0-9]+\.[0-9]{1}')) from mytable ;
Now i think its easy to fix it. You can try at your end also running this above queries.
Since your problem is not really the extended string literal syntax using E, but the string representation of the array in the IN list, your PL/pgSQL should look somewhat like this:
sql_query = sql_query ||
' AND substring(version from ' || quote_literal( '[0-9]+\.[0-9]{1}' ) ||
') IN (' || (SELECT string_agg(quote_literal(x), ', ')
FROM unnest(compatibleVersions
) AS x(x)) || ')';
quote_literal should be used in situations where u want to dynamically construct queries. In such situation quote_literal will be replaced by E in the final constructed query.
right way to use
select * from config_support_module where substring(firmware from '[0-9]+\.[0-9]{1}') IN ('6.2');
select * from config_support_module where substring(firmware from E'[0-9]+\.[0-9]{1}') IN ('6.2') ;
wrong usage of quote_literal in static queries
select * from config_support_module where substring(firmware from quote_literal('[0-9]+\.[0-9]{1}')) IN ('6.2') ;
This doesnt give you any errors/output.
quote_literal usage in dynamic queries
sql_query = sql_query || ' AND substring(version from ' || quote_literal( '[0-9]+\.[0-9]{1}' ) || ') ... .. ...
I'm struggling with a stored procedure which heavily uses dynamic queries. Among others I need to store maximum value of an existing column into a variable.
Postgres documents state "if you want to use dynamically determined table or column names, you must insert them into the command string textually". Based on that I've come up with following statement:
EXECUTE 'SELECT MAX(' || pkColumn::regclass || ') FROM ' ||
tableName::regclass INTO maxValue;
Table name seems to be OK, column name triggers error.
What am I doing wrong ?
Pavel
EXECUTE 'SELECT MAX(' || pkColumn ||'::regclass) FROM ' || ...
::regclass is a cast done inside query. You can also skip it, or put " - which in PG works the same. So please try one of:
EXECUTE 'SELECT MAX(' || pkColumn || ') FROM ' || ...
or
EXECUTE 'SELECT MAX("' || pkColumn || '") FROM ' || ...
All tree should work. If not - just let me know. In that case it is my fault, postgresql simply works.
There is no reason to cast parameters as they are just identifiers. For better control and readability use the function format(), e.g.:
declare
pkcolumn text = 'my_column';
tablename text = 'my_table';
...
execute format('select max(%I) from %I', pkcolumn, tablename)
into maxvalue;
Is there any way how to express a variable in PostgreSQL as a string?
Example:
\set table_name countries
SELECT 'SELECT * FROM ' || CAST( :table_name, 'text' ) AS specificQuery;
leads to this error:
ERROR: syntax error at or near ","
LINE 1: SELECT 'SELECT * FROM ' || CAST( countries, 'text' ) AS specificQuery;
From the line sample above is obvious, that it doesn't convert "countries" to a string, but it is expressed as name of column/table.
How do I convert it?
Are you looking for something like this?:
SELECT * FROM :"table_name";
http://www.postgresql.org/docs/current/interactive/app-psql.html#APP-PSQL-VARIABLES
Something like this :
SELECT 'SELECT * FROM ' || countries::text AS specificQuery;
I am attempting to semi automate creation of my databases
As part of this I want to add extended properties of column descriptions.
When I try to run sp_sqlexec in my script ( or even just Exec(#mystring) I get an error. However, if while debugging, I copy the dynamic sql string from the watch window and then run sp_sqlexec on the copied string in a seperate window I get no errors and the extended properties are added correctly.
The following script demonstrates the problem:
--Create a table to apply column descriptions to
Create table dbo.table1 (id int, name nvarchar(20));
--Create the table that contains our column descriptions
Create table dbo.column_descs_table (schemaname nvarchar(20), tablename nvarchar(20), columnname nvarchar(20), column_description nvarchar(20))
Insert into column_descs_table (schemaname, tablename, columnname, column_description)
values ('dbo', 'table1', 'id', 'the id column'), ('dbo' , 'table1', 'name', 'the name column');
--Dynamic sql string varaible to hold the commands
Declare #dyn_sql nvarchar(max);
Set #dyn_sql = 'N'''; --Set to opening quote
--now create the string containing commands to add column escriptions
SELECT #dyn_sql = #dyn_sql + N' EXEC sp_addextendedproperty ''''Col Desc'''', ''''' + column_description + N''''', ''''SCHEMA'''', ' + schemaname + N', ''''TABLE'''', ' + tablename + N', ''''COLUMN'''', ' + columnname + N' ;'
FROM dbo.column_descs_table
Set #dyn_sql = #dyn_sql + ''''; --add the closing quote
Print #dyn_sql --If I copy the contents of #dyn_sql here and run seperately it works OK
Exec sp_sqlexec #dyn_sql -- this line causes error
The error I get is
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ' EXEC sp_addextendedproperty 'Col Desc', 'the id column', 'SCHEMA', dbo, 'TABLE', table1, 'COLUMN', id ; EXEC sp_addextendedprope'.
Yet if I step through the code and copy the contents of #dyn_sql then paste this as follows:
Exec sp_sqlexec N' EXEC sp_addextendedproperty ''Col Desc'', ''the id column'', ''SCHEMA'', dbo, ''TABLE'', table1, ''COLUMN'', id ; EXEC sp_addextendedproperty ''Col Desc'', ''the name column'', ''SCHEMA'', dbo, ''TABLE'', table1, ''COLUMN'', name ;'
Then the above works fine and the column descriptions are added as expected.
Any help on this specific copying problem is much appreciated. I do understand the security issues with dynamic sql ( this script will be removed from the database once my setup is complete)
Thanks in advance
Jude
It looks like it's because your leading N is included within the string to execute; you don't need it at all. In other words, you are ending up with something like this:
exec sp_execsql 'N'' exec sp_addextendedproperty /* etc. */ '''
But it should be like this:
exec sp_execsql N'exec sp_addextendedproperty /* etc. */ '
But why are you even using dynamic SQL here? All values passed to sp_addextendedproperty can be passed as parameters so there is no obvious reason to use dynamic SQL, unless you've simplified something for the question.
Finally, you should be using sp_executesql, it's the preferred way to execute dynamic SQL.
I believe that I have resolved my string copying problem. SQL was detecting double quotes in by concatenated string as empty strings and removing them. A simple example showing the problem and my solution is below:
--Example to Select 'simple string' and then 'concat string' into results sets
DECLARE
#Simplestring nvarchar( max ) = '' ,
#Concatstring nvarchar( max ) = '' ,
#Stringvar nvarchar( 10 ) = 'string';
--The double quotes in next line are the quotemark we want plus a quotemark acting
--as an escape character
--#simplestring will be set to 'Select 'simple string' '
SET #Simplestring = 'Select ''simple string'' ';
--Similarly we need #concatstring to be set to 'Select 'Concat string' '
SET #Concatstring = 'Select '' concat' + #Stringvar + ''; -- this wont work the last
--double quote will be removed
--Add a character that cannot appear in any othe part of the concatenation - I've used *
SET #Concatstring = 'Select '' Concat ' + #Stringvar + '*';
--Now replace the * with a quote mark
SET #Concatstring = REPLACE( #Concatstring , '*' , '''' ); -- This will work
EXEC sp_executesql #Simplestring;
EXEC sp_executesql #Concatstring;
There may be a simpler solution than mine.
Many thanks for the advice on using sp_executesql. I am working on changing my code to use this ( with variables passed in as parametrs).
Jude