How to retrieve columns that end with one of characters in a list - sql

I'm trying to learn SQL and figuring out a way to retrieve all columns whose name ends with one of characters in an a list (using JDBC queries):
public Map<Long, Set<Long>> groupCountriesBy(Set<Integer> countryIdLastDigits) {
String query = "SELECT c.id FROM countries c"
+ " WHERE c.name LIKE '%[dea]'"
+ " GROUP BY c.name ";
var args = new MapSqlParameterSource("countryIdLastDigits", countryIdLastDigits);
....
}
WHERE c.name LIKE '%[dea]' does return all columns that end with either d, e or a, but I did not manage to find a way to pass countryIdLastDigits to this SQL query.
Could you please share with me some pointers / hints? Probably I'm missing few SQL concepts / commands.

Most SQL dialects have left and right string functions so perhaps something like
where right(col,1) in ('d', 'e', 'a')
will be all you need.

Related

How can I count all NULL values, without column names, using SQL?

I'm reading and executing sql queries from file and I need to inspect the result sets to count all the null values across all columns. Because the SQL is read from file, I don't know the column names and thus can't call the columns by name when trying to find the null values.
I think using CTE is the best way to do this, but how can I call the columns when I don't know what the column names are?
WITH query_results AS
(
<sql_read_from_file_here>
)
select count_if(<column_name> is not null) FROM query_results
If you are using Python to read the file of SQL statements, you can do something like this which uses pglast to parse the SQL query to get the columns for you:
import pglast
sql_read_from_file_here = "SELECT 1 foo, 1 bar"
ast = pglast.parse_sql(sql_read_from_file_here)
cols = ast[0]['RawStmt']['stmt']['SelectStmt']['targetList']
sum_stmt = "sum(iff({col} is null,1,0))"
sums = [sum_sql.format(col = col['ResTarget']['name']) for col in cols]
print(f"select {' + '.join(sums)} total_null_count from query_results")
# outputs: select sum(iff(foo is null,1,0)) + sum(iff(bar is null,1,0)) total_null_count from query_results

Hibernate, SQL in HQL (NativeQuery)

I am starting out at Hibernate. I am at the point, where I try out SQL in HQL.
I saw a code example which I wanted to recreate, but my output ended up being different.
To use SQL in HQL, that person said, if you want to only use a couple of columns, you need to use a Map to get certain columns (So I canĀ“t simply use addEntity here).
My Student table got sId, sName, sMarks. Now I want to retrieve only the Students names (sName) and their marks (sMarks).
The Problem is, that I only get "null" as values for the names and marks whilst the object shows me the proper values:
Console Output:
Hibernate: SELECT sName,sMarks FROM student
{SNAME=Nameless fool number 1, SMARKS=65}
null : null
The Code:
NativeQuery querySQL2 = session.createNativeQuery("SELECT sName,sMarks "
+ "FROM student");
querySQL2.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List students = querySQL2.getResultList();
for (Object o : students)
{
System.out.println(o);
Map m = (Map)o;
System.out.println(m.get("sName") + " : " + m.get("sMarks"));
}
Why do I get the proper Object with Syso(o) and just null with Syso(m.get("..."))?
Thank you in advance!
Actually you already answered your question
{SNAME=Nameless fool number 1, SMARKS=65}. Hibernate convert column names to upper case.

Using the results of a select sub query as the columns to select in the main query. Injection?

I have a table that contains a column storing sql functions, column names and similar snippets such as below:
ID | Columsql
1 | c.clientname
2 | CONVERT(VARCHAR(10),c.DOB,103)
The reason for this is to use selected rows to dynamically create results from the main query that match spreadsheet templates. EG Template 1 requires the above client name and DOB.
My Subquery is:
select columnsql from CSVColumns cc
left join Templatecolumns ct on cc.id = ct.CSVColumnId
where ct.TemplateId = 1
order by ct.columnposition
The results of this query are 2 rows of text:
c.clientname
CONVERT(VARCHAR(10),c.DOB,103)
I would wish to pass these into my main statement so it would read initially
Select(
select columnsql from CSVColumns cc
left join Templatecolumns ct on cc.id = ct.CSVColumnId
where ct.TemplateId = 1
order by ct.columnposition
) from Clients c
but perform:
select c.clientname, CONVERT(VARCHAR(10),c.DOB,103) from clients c
to present a results set of client names and DOBs.
So far my attempts at 'injecting' are fruitless. Any suggestions?
You can't do this, at least not directly. What you have to do is, in a stored procedure, build up a varchar/string containing a complete SQL statement; you can execute that string.
declare #convCommand varchar(50);
-- some sql to get 'convert(varchar(10), c.DOB, 103) into #convCommand.
declare #fullSql varchar(1000);
#fullSql = 'select c.clientname, ' + #convCommand + ' from c,ients c;';
exec #fullSql
However, that's not the most efficient way to run it - and when you already know what fragment you need to put into it, why don't you just write the statement?
I think the reason you can't do that is that SQL Injection is a dangerous thing. (If you don't know why please do some research!) Having got a dangerous string into a table - e.g 'c.dob from clients c;drop table clients;'- using the column that contains the data to actually execute code would not be a good thing!
EDIT 1:
The original programmer is likely using a C# function:
string newSql = string.format("select c.clientname, {0} from clients c", "convert...");
Basic format is:
string.format("hhh {0} ggg{1}.....{n}, s0, s1,....sn);
{0} in the first string is replaced by the string at s0; {1} is replaces by tge string at s1, .... {n} by the string at sn.
This is probably a reasonable way to do it, though why is needs all the fragments is a bit opaque. You can't duplicate that in sql, save by doing what I suggest above. (SQL doesn't have anything like the same string.format function.)

Basic - SQL Query to LINQ Query

I have been trying out some LINQ query can someone please show how to convert the following SQL query to LINQ:
SELECT *, firstname+' '+lastname AS FullName FROM Client WHERE age > 25;
Don't worry about the where part (put it in for completeness) more wandering how to achieve that first part.
Now I have come across something like this:
from c in dc.Clients select new {FullName = c.firstname + " "+c.lastname}
But i don't know how to get it to select everything else without specifying it ie:
{firstname = c.firstname, id = c.id ..... etc}
But I was hoping for another way of achieving that.
So I'm just wandering if someone could show me the right or another way of accomplishing this :)
Thanks All :)
You have to select the actual item then refer to its properties. There's no way to expand the individual columns into the anonymous type.
var query = from c in dc.Clients
where c.Age > 25
select new
{
Client = c,
FullName = c.firstname + " " + c.lastname
};
foreach (var item in query)
{
// item.Client.Id
// item.FullName
// item.Client.FirstName
}
Selecting the actual item gives you access to the same properties you were using to construct the anonymous type. It's not a complete waste though if the query had more going on, such as a join with another table and including fields from that result in the anonymous type, along with the entire Client object.
You can can't autogenerate every column with Linq2Sql or EF (you can however find a way to mimic this behavior with micro-orms like Dapper and massive).
More conveniently, you can just select a new anonymous type with 3 fields, firstname, lastname and a client like:
from c in dc.Clients
select new
{
FullName = c.firstname + " "+c.lastname,
Client = c
}
I would however recommend to select just those properties that you really need. This forces you to think about how to compose your query and what the query is intended to do (and hence, select). Alternatively, you can just select the client, and use some extension methods to select full names. like:
public static string GetFullName(this Client client){ return client.firstname + " " + client.lastname; }

constructing dynamic In Statements with sql

Suppose we need to check three boolean conditions to perform a select query. Let the three flags be 'A', 'B' and 'C'.
If all of the three flags are set to '1' then the query to be generated is
SELECT * FROM Food WHERE Name In ('Apple, 'Biscuit', 'Chocolate');
If only the flags 'A' and 'B' are set to '1' with C set to '0'. Then the following query is generated.
SELECT *
FROM Food
WHERE Name In ('Apple, 'Biscuit');
What is the best way to do it?
SELECT *
FROM Food
WHERE (Name = 'Apple' AND <condition A>)
OR (Name = 'Biscuit' AND <condition B>)
OR (Name = 'Chocolate' AND <condition C>)
Now, while being correct this is not desirable from performance point of view since conditions A, B, and C are not data driven (they don not change from row to row). So you can use permutations of all possible conditions by constructing SQL dynamically - use IN clause and construct its string dynamically.
Yet another solution is assembling final result in the client by running each SELECT separately (pseudo-code):
if A then {
result1 = execute("SELECT * FROM Food WHERE Name = 'Apple')
}
if B then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Biscuit')
}
if C then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Chocolate')
}
result = join(result1, result2, result3)
This solution may work when you have high percentage of cases with just one or two true conditions.
First may be you need to check if all are false and show error. Or may be not if it is acceptable in your case.
Then if these flags are mere bool variables do (pseudocode)
sql = "SELECT *
FROM Food
WHERE Name In (";
if (A) sql += "'Apple', "
if (B) sql += "'Biscuit', "
if (C) sql += "'Chocolate', "
sql = sql.deleteLastCharacter() + ");";
Why don't you include A/B/C in the query?
select * from food where (name = 'Apple' or NOT A) and (name = 'Biscuit' OR NOT B)...
I think this should be read: Dynamic SQL.
The sp_executesql system stored procedure reveals to be pretty useful also.
This is a really complex topic that has many subtle performance implications. You really need to read these excellent articles by Erland Sommarskog:
Dynamic Search Conditions in T-SQL
The Curse and Blessings of Dynamic SQL