Criteria. Select biggest of two - sql

I'm stuck when rewriting fairly simple pure sql statement to criteria queries.
Basically I can simplify my query to
select max(T.value, S.value) from T, S where T.id = S.id
I have tried
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root<T> fromT = cq.from(T.class);
Root<S> fromS = cq.from(S.class);
cq.where(cb.equal(fromT.get("id), fromS.get("id"));
cq.select(); // <---- what to put here.
getEntityManager().createQuery(cq).getResultList();
I found greatest method but it compares horizontally (values from column) and I would like to compare two values from the same row but different column and get one with biggest value.
Only solution which comes to me mind is to get the results and sort them 'manually' but this can influence performance.

You can try the below case statement.
cb.selectCase().
when(cb.greaterThanOrEqualTo(fromT.get("xValue"), fromS.get("yValue")), fromT.get("xValue")). //-- If T has max value
otherwise(fromS.get("yValue")); //-- Else, by default select value from S

Can you just use a case statement?
SELECT
CASE
WHEN T.value < S.value THEN S.value
ELSE T.value
END
FROM
T, S
WHERE
T.id = S.id
I would also suggest changing this to an inner join if at all possible:
SELECT
CASE
WHEN T.value < S.value THEN S.value
ELSE T.value
END
FROM
T INNER JOIN S
ON T.id = S.id

Related

How to use cross apply with Sql Kata

I am dont know to construct a query with Cross Apply and SqlKata. I was searching the net and I find out that cross apply was not supported by SqlKata. Is there any other way to achieve my requirements.
var query = new Query("Test as t")
cross apply
(select top 1 t2.TestID from Test as t2 where t1.LegID = t2.LegID order by t2.Sequence desc)
This is the sql query
select * from Test1 t1
cross apply
(select top 1 s.OperationalStopID
from Test2 t2
where t2.LegID = t1.LegID
order by t2.SequenceNumber desc) t3
Just use the Join method and pass "CROSS APPLY" or whatever method you like in the last parameter
check this example on SqlKata Playground
var another = new Query("Test2 as t2")
.WhereColumns("t2.LegID", "=", "t1.LegID")
.Select("s.OperationalStopID")
.OrderByDesc("t2.SequenceNumber")
.Limit(1);
var query = new Query("Test1 as t1").Join(another.As("t3"), j => j, "CROSS APPLY"); // <---
I am not familiar with sqlkata, but you can rewrite your SQL query to an inner join, like:
select DISTINCT
t1.I,
t1.LegID,
x.OperationalStopID
from test1 t1
inner join (select LegID, MAX(OperationalStopID) as OperationalStopID
from test2
group by LegID) x on x.LegID = t1.LegID
I hope you are able to convert this SQL query to sqlkata syntax ?
This query is tested here: DBFIDDLE
P.S.: oops, the DISTINCT should not have been in there anymore, please remove it.

SQL Filling In Values From A Second Table

I came up with this query to fill in a missing field from a second table using a subquery.
I can not modify the original table
SELECT
CASE WHEN original.target_field IS NULL THEN
(SELECT fill_in.target_field FROM second.table fill_in
WHERE original.id = fill_in.id)
ELSE
original.target_field END AS myField
FROM
primary.table original
I was wondering if I was missing something and if there was a more performant way to do this?
You could use LEFT JOIN and COALESCE instead of correlated subquery:
SELECT COALESCE(original.target_field,fill_in.target_field) AS myField
FROM primary.table original
LEFT JOIN second.table fill_in
ON original.id = fill_in.id
It is always worth testing different methods. But your query should be fine with an appropriate index.
I would write it as:
SELECT (CASE WHEN o.target_field IS NULL
THEN (SELECT f.target_field
FROM second.table f
WHERE o.id = f.id
)
ELSE o.target_field
END) AS myField
FROM primary.table o;
You want an index on second.table(id, target_field). You would want the same index for the LEFT JOIN version.

Join SQL Server Showing Duplicate Row

I want to ask something about joining query. I have a query like this:
SELECT b.compilecodingid,
a.subjobfamily,
b.position,
b.nocoding,
( CASE
WHEN (SELECT Count(0)
FROM trlspbia
WHERE learningsystemid = a.learningsystemid
AND compilecodingid = b.compilecodingid
AND moduleid = '2018081616230361362303614'
AND learningroadmap = 'Basic') > 0 THEN 1
ELSE 0
END ) AS CountPickPBIA
FROM trlsplanning a,
trcompilecodingheader b
WHERE a.learningsystemid = b.learningsystemid
AND a.position = b.position
AND a.learningsystemid = '2018081513283162000000001'
order by CountPickPBIA desc
I know it's because Column Position on Table TrLsPlanning has more than 1 data,
Anyone can help me to find the solution?
Thank you.
The simplest solution is probably select distinct:
SELECT cch.compilecodingid, p.subjobfamily, cch.position, cch.nocoding,
(CASE WHEN EXISTS (SELECT 1
FROM trlspbia s
WHERE s.learningsystemid = p.learningsystemid AND
s.compilecodingid = ccb.compilecodingid AND
s.moduleid = '2018081616230361362303614' AND
s.learningroadmap = 'Basic'
)
THEN 1
ELSE 0
END) AS CountPickPBIA
FROM trlsplanning p JOIN
trcompilecodingheader cch
ON p.learningsystemid = cch.learningsystemid AND
p.position = cch.position
WHERE p.learningsystemid = '2018081513283162000000001'
ORDER BY CountPickPBIA DESC;
SELECT DISTINCT incurs its own overhead. But without more information about the structure and contents of the table, this is the simplest solution.
Note other changes in the query:
Table aliases are abbreviations for table names, rather than being arbitrary letters.
The JOIN syntax is fixed, to use modern, proper, and standard JOIN/ON.
All columns are qualified with the table alias, particularly those in the correlated subqueries.
The subquery uses EXISTS rather than COUNT(*). This is both more efficient and it probably better expresses the logic you want.

Handling null in subquery

SELECT *
FROM myTable m
WHERE m.userId = :userId
AND m.X = (SELECT MAX(X)
FROM myTable m
WHERE m.userId = :userId
AND m.contactNumber = :contactNumber)";
The problem is,second part of statement evaluates to null in case no such row is present and the statement fails to execute.I want the result to be empty in such a case.
One way to solve this problem is to do expensive filesort(order by) and then fetch the required field at code level. Any better solution to this problem ?
Can you use ISNULL?
and m.X = ISNULL(, '')
I'm not sure why you're getting NULLs here, but try this:
SELECT myTable.*, IF myTableMax.myMaxX IS NOT NULL myTableMax.myMaxX ELSE ""
FROM myTable
LEFT OUTER JOIN
(SELECT userID, contactNumber, MAX(X) AS myMaxX
FROM myTable
GROUP BY userID, contactNumber) AS myTableMax
ON myTable.userID = myTableMax.userID
AND myTable.contactNumber = myTableMax.contactNumber
WHERE myTable.userID = :userID
AND myTable.contactNumber = :contactNumber
If you're concerned about performance, add an index on mytable (userID, contactNumber).

SQL Server: Logical equivalent of ALL query

I have a following query (simplified):
SELECT
Id
FROM
dbo.Entity
WHERE
1 = ALL (
SELECT
CASE
WHEN {Condition} THEN 1
ELSE 0
END
FROM
dbo.Related
INNER JOIN dbo.Entity AS TargetEntity ON
TargetEntity.Id = Related.TargetId
WHERE
Related.SourceId = Entity.Id
)
where {Condition} is a complex dynamic condition on TargetEntity.
In simple terms, this query should return entities for which all related entities match the required condition.
Unfortunately, that does not work quite well, since by SQL standard 1 = ALL evaluates to TRUE when ALL is applied to an empty set. I know I can add AND EXISTS, but that will require me to repeat the whole subquery, which, I am certain, will cause problems for performance.
How should I rewrite the query to achieve the result I need (SQL Server 2008)?
Thanks in advance.
Note: practically speaking, the whole query is highly dynamic, so the perfect solution would be to rewrite only 1 = ALL ( ... ), since changing top-level select can cause problems when additional conditions are added to top-level where.
Couldn't you use a min to achieve this?
EG:
SELECT
Id
FROM
dbo.Entity
WHERE
1 = (
SELECT
MIN(CASE
WHEN {Condition} THEN 1
ELSE 0
END)
FROM
dbo.Related
INNER JOIN dbo.Entity AS TargetEntity ON
TargetEntity.Id = Related.TargetId
WHERE
Related.SourceId = Entity.Id
)
The min should return null if there's no clauses, 1 if they're all 1 and 0 if there's any 0's, and comparing to 1 should only be true for 1.
It can be translated to pick Entities where no related entities with unmatched condition exist.
This can be accomplished by:
SELECT
Id
FROM
dbo.Entity
WHERE
NOT EXISTS (
//as far as I have an element which do not match the condition, skip this entity
SELECT TOP 1 1
FROM
dbo.Related
INNER JOIN dbo.Entity AS TargetEntity ON
TargetEntity.Id = Related.TargetId
WHERE
Related.SourceId = Entity.Id AND
CASE
WHEN {Condition} THEN 1
ELSE 0
END = 0
)
EDIT: depending on condition, you can write something like:
WHERE Related.SourceId = Entity.Id AND NOT {Condition} if it doesn't change too much the complexity of the query.
Instead of using all, change your query to compare the result of the subquery directly:
select Id
from dbo.Entity
where 1 = (
select
case
when ... then 1
else 0
end
from ...
where ...
)
Probably this will work: WHERE NOT 0 = ANY(...)
If I read the query correctly, it can be simplified to something like:
SELECT e.Id
FROM dbo.Entity e
INNER JOIN dbo.Related r ON r.SourceId = e.Id
INNER JOIN dbo.Entity te ON te.Id = r.TargetId
WHERE <extra where stuff>
GROUP BY e.Id
HAVING SUM(CASE WHEN {Condition} THEN 1 ELSE 0 END) = COUNT(*)
This says the Condition must be true for all rows. It filters the "empty" set case away with the INNER JOINs.