Suppose I have a SQL like that:
SELECT a.*
FROM A a
LEFT JOIN
B b
JOIN C c ON (c.b_id = b.id AND c.whatever > 0)
ON (a.id = b.a_id)
Now I start coding using the criteria API:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<A> criteria = builder.createQuery(A.class);
Root<A> a = criteria.from(A.class);
Now what?
I can't Join<A, B> b = a.join("b") yet.
The a.join(???) should be called over something else, that happens to have b defined.
That something else is the result of joining together B and C (plus a custom ON clause, stating that only some Cs - those with whatever bigger than zero - are acceptable). That something else still exposes B and C separately (for further predicate filtering with where and/or column projection with select).
UPDATE
What's the difference between
(1) A a LEFT JOIN (B b JOIN C c ON (c.b_id = b.id AND c.whatever > 0)) ON (a.id = b.a_id); and
(2) (A a LEFT JOIN B b ON (a.id = b.a_id)) JOIN C c ON (c.b_id = b.id AND c.whatever > 0)?
[parenthesis were added for clarity; they are never required]
The ON clause can be understood as "closing" the last "still open" JOIN. The JOIN clause (any type) can be understood as "opening" a new JOIN; these JOINs are stacked on "opening" and unstacked on "closing".
In (1), the order is: I-JOIN(B and C), then L-JOIN(A and that).
In (2), the order is: L-JOIN(A and B), then I-JOIN(that and C).
[I-JOIN is an INNER JOIN and L-JOIN is a LEFT OUTER JOIN]
For the sake of simplicity, just take the table C to be empty. So, no matter what JOIN you make, any reference to C (i.e. to its columns) will always be NULL.
Now, in (1) there will be one result per row in A. Because I-JOIN(B and C) will always produce no rows (remember, C is empty, so any INNER JOIN is empty too); then L-JOIN(A and empty) will produce A and all columns from B and C will be NULL.
In (2) the result will be totally empty. No matter how many rows L-JOIN(A and B) produces (there will be at least one row per row of A), the final INNER JOIN with empty C entails an empty result (no rows at all).
Related
In my JPA model there are 3 tables A, B, C.
My query is:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c LEFT JOIN B b"
ON c = b.c AND b.a = a
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil AND b.a IS NULL
)
Background is that I want all entities of A that do not have an entry in b that is linked to an event C in the future.
The problem is that I get Column 'T0.ID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or ...
EDIT
: Think of it as A is a user table, C are events, and B stores the registrations of users for events. I want to get all users, which have not registered for all future events until parameter pUntil.
Although I agree with Neil, I worked around this issue by changing my query. Here's the new query:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil
AND NOT EXISTS (
SELECT b from B b
WHERE b.c= c and b.a = a
)
)
I'm trying to write a JPQL query which should get a list which match atleast one of two conditions. When I construct the queries sepperatly they work as expected, but putting them together in an 'OR' returns a list which only match one of the conditions. I don't understand why this is.
This is the full query:
SELECT a FROM Article a WHERE ((a.ag.proteinPID.uniprot.AC LIKE :genProt)
OR (a.aid IN(SELECT a2.aid FROM Protein p JOIN p.articleList a2 WHERE p.uniprot.AC LIKE :genProt)))
And the sepperate ones:
1)
SELECT a FROM Article a WHERE a.aid IN(SELECT a2.aid FROM Protein p JOIN p.articleList a2 WHERE p.uniprot.AC LIKE :genProt)
2)
SELECT a FROM Article a WHERE a.ag.proteinPID.uniprot.AC LIKE :genProt
The full expression returns the same result as expression 2).
Try left joining the entities within the full query for the first condition:
SELECT a FROM Article a LEFT JOIN a.ag g LEFT JOIN g.proteinPID p LEFT JOIN p.uniport u WHERE ((u.AC LIKE :genProt)
OR (a.aid IN(SELECT a2.aid FROM Protein p JOIN p.articleList a2 WHERE p.uniprot.AC LIKE :genProt)))
Why this works: if do not explicitly left join, I suppose it makes an INNER JOIN which automatically will limit the results.
I have a table x which have the fields a, b, c, and d. I want to do a SELECT statement which is GROUPED BY a HAVING a_particular_value = ANY(array_agg(b)) and retrieves a, MIN(d), and c <- from which row is chosen by a_particular_value = ANY(array_agg(b)).
It's a bit confusing.
Lemme try to explain. a_particular_value = ANY(array_agg(b)) will choose some or one record from all records that is grouped by a. I want to retrieve the value of c from the record that causes the condition to be true. While NOT filter out other records because I still need those for the other aggregate function, MIN(d).
The query that I've tried to make:
SELECT a, MIN(d) FROM x
GROUP BY a
HAVING 1 = ANY(array_agg(b))
The only thing that's left to do is put c in the SELECT clause. How do I do this?
with agg as (
select a, min(d) as d
from x
group by a
having 1 = any(array_agg(b))
)
select distinct on (a, c)
a, c, d
from
x
inner join
agg using (a, d)
order by a, c
If min(d) is not unique within the a group then it is possible to exist more than one corresponding c. The above will return the smallest c. If you want the biggest do in instead
order by a, c desc
c can have various values in this scenario, so your only option is to group by c as well.
SELECT a, c FROM x
GROUP BY a, c
HAVING 1 = ANY(array_agg(b))
If you want to eliminate rows with b not satisfying condition before applying GROUP BY then use WHERE as documentation for HAVING says http://www.postgresql.org/docs/9.2/static/sql-select.html#SQL-HAVING
The relationship:
Profil>Branch>City
Profil>Hotel>City
command:
from p in Profil.getData()
join b in Branch.getData() on p equals b
join h in Hotel.getData() on p equals h
join c in City.getData()
^how to reuse the equals join
Can I join City to Branch and Hotel table?
Can I just clone the c without City.getData()?
Sure, just do (following your pseudo code):
from p in Profil.getData()
join b in Branch.getData() on p equals b
join h in Hotel.getData() on p equals h
join c1 in City.getData() on b equals c1
join c2 in City.getData() on h equals c2
EF will translate this into two aliases for the City table. So you don't reuse or clone the cities, but in SQL that's not possible either. SQL server will be able to optimize it in the query's execution plan though.
When joining two tables, what are the difference between the two blocks below and which is the better approach?
Pattern A:
SELECT ...
FROM A
INNER JOIN B
ON A.PK = B.FK
WHERE 1=1
AND A.Name = "Foo"
AND B.Title = "Bar"
Pattern B:
SELECT ...
FROM A
INNER JOIN B
ON A.PK = B.FK
AND B.Title = "Bar"
WHERE 1=1
AND A.Name = "Foo"
This is going to differ from person to person, but I think that Pattern A is better.
What it does is it separates the table level joins from the filters. This could be helpful for queries with multiple joins and multiple filters because it clearly separates the two types of joining that is going on.
I prefer pattern A, but there is probably not any difference. You really have to look at the execution plan though to make sure it is running efficiently.
If you replace INNER JOIN with OUTER JOIN, there will be difference.
Otherwise, these queries:
SELECT ...
FROM A
INNER JOIN
B
ON A.PK = B.FK
WHERE A.Name = "Foo"
AND B.Title = "Bar"
SELECT ...
FROM A
INNER JOIN
B
ON A.PK = B.FK
AND B.Title = "Bar"
WHERE A.Name = "Foo"
SELECT *
FROM A, B
WHERE B.Title = "Bar"
AND A.Name = "Foo"
AND A.PK = B.FK
are identical.
Oracle, MySQL, PostgeSQL and SQL Server will treat them exactly the same, and use exactly same plan for all of them.
I'd use this one:
SELECT ...
FROM A
INNER JOIN
B
ON B.FK = A.PK
WHERE A.Name = "Foo"
AND B.Title = "Bar"
if there is a single-column key on B.FK, and this one:
SELECT ...
FROM A
INNER JOIN
B
ON B.FK = A.PK
AND B.Title = "Bar"
WHERE A.Name = "Foo"
if there is a composite key on (B.FK, B.title).
The join conditions are more visual in this case.
I may be wrong on this, but i see the 1st approach as a more efficient one. Your queries are executed inside-out. So when you run your join first, it'll run faster just because it has to match on (probably indexed) PK & FK Fields and not anything extraneous like your Title field ( which is probably a varchar, making the match even slower). So, by the time you get to your filtering where clause, you have less data to perform matching on. Total speculation though. I wonder what others would say. Wouldn't hurt to see the execution plan on this :)