I am writing a PL/pgSQL function. The function has input parameters which specify (indirectly), which tables to read filtering information from.
The function embeds business logic which allows it to select data from different tables based on the input arguments. The function dynamically builds a subquery which returns filtering data which is then used to run the main query.
My questions are:
Is it 'legal' to use a dynamic subquery in a PL/pgSQL function. I cant see why not - but this question is related to the next one.
AFAIK, PL/pgSQL are cached or precompiled by the query engine. How does having a function that generates dynamic subqueries impact the work of the query engine?
"38.5.4. Executing Dynamic Commands"
Related
I have a quite complicated data structure that lies in several tables. I have a function that makes a copy of that structure. I want to make a copy and get newly created data in a single query like this:
SELECT
*
FROM
main_table
JOIN other_table
ON (main_table.id = other_table.main_id)
WHERE
main_table.id = make_copy(old_id);
The copy is successfully created, but is not returned by the above query. I guess it is not yet visible for the outer query or somehow committed.
I have also tried to use WITH ... SELECT ... but with no success...
The function make_copy(id) is declared as VOLATILE because it modifies the database, and multiple calls with the same parameter will create multiple copies.
Possible solution could be that make_copy(id) function would return the whole new data structure (SELECT * FROM make_copy(old_id)) but it would require many aliasing (many tables have id or name column). Also I would end up with many places to build (read) that data structure.
How can I call that function and use its result (and all side effects) in one query?
I'm afraid that's not possible without splitting it into two queries.
CTE can't help you - Data-Modifying Statements in WITH (See there example with updating table inside of the cte):
...The sub-statements in WITH are executed concurrently with each
other and with the main query. Therefore, when using data-modifying
statements in WITH, the order in which the specified updates actually
happen is unpredictable. All the statements are executed with the same
snapshot (see Chapter 13), so they cannot “see” one another's effects
on the target tables. This alleviates the effects of the
unpredictability of the actual order of row updates, and means that
RETURNING data is the only way to communicate changes between
different WITH sub-statements and the main query...
And I guess you cannot do this with function either - Function Volatility Categories:
For functions written in SQL or in any of the standard procedural
languages, there is a second important property determined by the
volatility category, namely the visibility of any data changes that
have been made by the SQL command that is calling the function. A
VOLATILE function will see such changes, a STABLE or IMMUTABLE
function will not. ... VOLATILE functions obtain a fresh snapshot at
the start of each query they execute.
I have next issue:
I have list of names, based on which I want to filter.The problem is that I have not full names(Because I'm receiving them from ui), and I have, for example, this array= ['Joh', 'Michae'].
So, I want to filter based on this array.
I wrote query in PostgreSQL
select * from q_ob_person where name like any (array['%Хомяченко%', '%Вартопуз%']);
And I want to ask how to write JPQL query gor this.
Is there an option to call postgresql function like any from JPQL?
JPA 2.1 allows invocation of any SQL function using
FUNCTION(sqlFuncName, sqlArgs)
So you could likely do something like (note never tried this LIKE ANY you refer to, just play around with it)
FUNCTION("LIKE", FUNCTION("ANY", arrayField))
Obviously by invoking SQL functions specific to a particular RDBMS you lose database independence (in case that's of importance).
I asked a question yesterday about a procedure we're trying to re-write/optimize in our application. It's off of a search form with a bunch of criteria the user can specify. 40 parameters, 3 of which are long strings of Guids that I am passing into a UDF that returns a Table variable, all 3 of which we JOIN into our main FROM statement.
We did much of this query using Dynamic SQL, one of the main reasons we're re-writing the whole thing is because it's Dynamic SQL. Everything I ever read about Dynamic SQL is bad, especially for execution plans and optimization. Then I start coming across articles like these two....
Sometimes the Simplest Solution isn't the Best Solution
Erland Sommarskog - Dynamic SQL Conditions in T-SQL
I've always though Dynamic SQL was bad for security and optimization, we've tried removing it form our system wherever possible. Now we're restructuring the most executed query in our system (main search query) and we thought stripping all the Dynamic SQL was going to help.
Basically replacing
IF(#Param1 IS NULL)
#SQLString = #SQLString + " AND FieldX = #Param1"
...execute the #SQLString
with one large SQL block that has
WHERE (#Param1 IS NOT NULL AND FieldX = #Param1)
Reading those two articles it seems like this is going to work against me. I can't use RECOMPILE because we're in 2k5 still and even if we could this stored procedure is very high-use. Do I really want to write this Query in Dynamic SQL? How can it be faster if no execution plans can be stored?
I have a bunch of dimension tables that have unique ID and Name fields. I need a T-SQL function that returns an ID when passed a table name and a value for the name field.
I'm guessing the function would build a little query then execute it? Performance isn't an issue since this is a one time ETL thing.
Sounds like you want a scalar user defined function
There's a lot of other ways to do it though, and udf's certainly can have some perfomance issues.
Is it possible to use the name of a table as a parameter in t-sql?
I want to insert data into a table, but I want one method in C# which has a parameter for the table.
Is this a good approach? I think if I have one form and I am choosing the table and fields to insert data into, I am essentially looking to write my own dynamic sql query built on the fly. This is another thing altogether which I am sure has its catches?
Thanks
Not directly. The only way to do this is through dynamic SQL - either EXEC or sp_ExecuteSQL. The latter has the advantage of query cache/re-use, and avoiding injection via parameters for the values - but you will have to concatenate the table-name itself into the query (you can't parameterise it), so be sure to white-list it against a list of known-good table names.