In my JDBC template, I want to execute a PostgreSQL function for certain rows. Currently, I do:
JdbcTemplate t = ...;
String q = "select my_function(table.identifier) from table where ...`;
template.query(q, new Object[]{...}, result -> null);
Here result -> null is a ResultSetExtractor which just ignores the result set and results null. I am doing this because I don't really care about the result of the my_function function. I just want to execute it for the selected rows.
Is there a cleaner way to do this? While it works perfectly, it's kinda hackisch, in my opinion at least.
If you want to avoid that the result is sent to the client at all, use PL/pgSQL's PERFORM in a DO statement:
DO $$BEGIN PERFORM myfunction(...) FROM ...; END;$$;
You simply put PERFORM in the place where you would normally write SELECT.
I will admit that this is also kind of a hack, but at least it has a clear performance advantage.
Related
I have a somewhat complicated #Query in a JpaRepository.
I need to get the results of this query in two forms (but not at the same time!):
First, the client asks for a count of the number of results: SELECT COUNT(x.*) FROM my_table x ...
Then later (maybe), they want to see the actual data: SELECT x.* FROM my_table x ...
What follows (the ...) is identical for both queries. Is there any way to combine these so that I don't repeat myself?
I know I could just use the second method, and count the number of elements in the resulting List. However, this adds the overhead of actually fetching all those elements from the database.
I could put the ... in a String constant somewhere, but that kind of separates it from its context (I'd lose IntelliJ's syntax highlighting/error checking)
I can't convert it to a Criteria or Example query, because I need to use PostGIS's geography type. (And these are less readable anyway...)
Any other ideas?
If your worries is about some developer change the COUNT query and forgot to change the SELECT query too, you can create a repository integration test to guarantee the expected result between the two queries.
Another alternative is create a unit test to read the annotation content and verify if the final of these two queries are equal.
How can i dynamically transform an SQL-Query?
I know there is a Select.getSelect(), but how can i add fields in the select-query?
Use-case: for a Rest-Query i have a lot of paginated resources and i have an abstraction to create the paginated-query. It takes the SelectConditionStep and adds the rest, depending on additional parameters. It works really well for simple queries, but for queries containing joins a little bit of transformation of the query would required. (Mainly because i can't naively limit the number results, since the join can be a one to many relationship)
The easiest way is to keep a List<Field<?>> where you add the fields for your select() clause, and then create the Select statement only when you actually execute it, instead of passing a Select object around. Example:
List<Field<?>> fields = new ArrayList<>();
// Just some examples:
fields.addAll(getDefaultFields());
fields.addAll(getFieldsFromUI());
fields.addAll(getCalculatedFields());
// Much later on, you finally create the statement:
DSL.using(configuration)
.select(fields)
.from(...)
.fetch();
If I run execute("SELECT * FROM users WHERE id = 1")[0][0], I'll get back the first field from the first row of that resultset.
If I run prepare("SELECT * FROM users WHERE id = ?").execute(1)[0][0], which to me seems like it should return an identical result, I get the error [] NoMethodError.
I can't for the life of me figure out why and the documentation seems really sparse. What's going on?
Your two execute methods are not identical and are returning different things.
In the first instance, you are calling execute on Database, which returns a simple array. Then you correctly index into it with [].
However, prepare returns a Statement object which you then call execute on. This instead returns a ResultSet, which doesn't have the same semantics as an array.
You might be looking for execute!.
I have a block based on a table. If I enter "12345" in enter query mode, it creates a query with
WHERE my_field = '12345'
If I enter "12345A", it goes
WHERE (upper(my_field) = '12345A' AND my_field like '12%')
which is bad, because my_field is indexed normally (not on upper(my_field)). I have tried toggling "Case restriction" attribute between mixed and upper, and "Case insensitive query" between yes and no, nothing seems to help. I also have a block level PRE-QUERY trigger (trigger starts with a RETURN; statement) set on override, so nothing should mess with the formation of the query, yet it still messes up.
Any ideas on what else I could try?
EDIT:
There was an obscure function call within WHEN_NEW_FORM_INSTANCE trigger to some attached library that reset all trigger block's items to CASE_SENSITIVE_QUERY = TRUE. Never would have guessed.
Not sure how the query is getting changed to that form;
WHERE (upper(my_field) = '12345A' AND my_field like '12%'
First check that there are no enter query or prequery triggers in the form. Somebody might have attached a trigger at a higher level. Oracle is not that smart to rewrite the query.Check that you are tying to a table not a view or stored procedure,...
If all else fails, enable the query triggers in the data black and rewrite the where clause yourself. It is pretty straightforward.
Give version of oracle forms before you post.
The
my_field like '12%'
Uses the index. The subset is then filtered with
upper(my_field) = '12345A'
So it might not be as bad as you think....
The most naive question, Can you update the column so it's all uppercase? I mean would it cause some inconvenience to your app?
If you can, it could be handled with a database trigger to ensure it's allways uppercase.
If you can't, then I suggest you create another field that you keep updated to uppercase with a database trigger.
You can also create a function index so it's upper(my_field).
I'm tasked with adding an option to our search, which will return results where a given field doesn't begin with a letter of the alphabet. (The .StartsWith(letter) part wasn't so hard).
But I'm rather unsure about how to get the results that don't fall within the A-Z set, and equally hoping it generates some moderately efficient SQL underneath.
Any help appreciated - thanks.
In C# use the following construct, assuming db as a data context:
var query = from row in db.SomeTable
where !System.Data.Linq.SqlClient.SqlMethods.Like(row.SomeField, "[A-Z]%")
select row;
This is only supported in LINQ to SQL queries. All rules of the T-SQL LIKE operator apply.
You could also use less effective solution:
var query = from row in db.SomeTable
where row.SomeField[0] < 'A' || row.SomeField[0] > 'Z'
select row;
This gets translated into SUBSTRING, CAST, and UNICODE constructs.
Finally, you could use VB, where there appears to be a native support for the Like method.
Though SQL provides the ability to check a range of characters in a LIKE statement using bracket notation ([a-f]% for example), I haven't seen a linq to sql construct that supports this directly.
A couple thoughts:
First, if the result set is relatively small, you could do a .ToList() and filter in memory after the fact.
Alternatively, if you have the ability to change the data model, you could set up additional fields or tables to help index the data and improve the search.
--EDIT--
Made changes per Ruslan's comment below.
Well, I have no idea if this will work because I have never tried it and don't have a compiler nearby to try it, but the first thing I would try is
var query = from x in db.SomeTable
where x.SomeField != null &&
x.SomeField.Length >= 1 &&
x.SomeField.Substring(0, 1).All(c => !Char.IsLetter(c))
select x;
The possiblility exists that LINQ to SQL fails to convert this to SQL.