JPA 2.0 LEFT JOIN induces INNER JOIN - jpa-2.0

I have a ClassRoom class with a name field, and a Student class with a ClassRoom field. Not all students have a classroom.
I want a list of all students with their classroom name (or an empty string if no classroom). Using this JPQL query :
Select s.name, s.classRoom.name from Student s LEFT JOIN s.classRoom
The problem is that this returns only students with a classroom. The right generated SQL should be
Select s.name, c.name from student s left join classroom c on c.id=s.classroomid
Which returns all students, but the s.classRoom.name construct seems to force an inner join in the generated SQL.

Using a chained expression like s.classRoom.name generates an inner join. You need to assign an alias to the left joined entity and use that alias:
select s.name, c.name from Student s left join s.classRoom c

Related

How do you query table names and row counts for all tables in a schema using HP NonStop SQL/MX?

How do you query table names and row counts for all tables in a schema using HP NonStop SQL/MX?
Thanks!
This might help you, althought this is more standard SQL and im not sure how much variation comes into sqlmx
SELECT
TableName = t.NAME,
TableSchema = s.Name,
RowCounts = p.rows
FROM
sys.tables t
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE
t.is_ms_shipped = 0
GROUP BY
t.NAME, s.Name, p.Rows
ORDER BY
s.Name, t.Name
Obviously this is an example, replace example data and table info with yours
Here is how to list the tables in a sql/mx schema, note that the system catalog name given here is an example, replace NONSTOP_SQLMX_SYSNAME with NONSTOP_SQLMX_xxxx where xxxx is the Expand node name of your system.
Also the definition schema name includes the schema version number, this example uses 3600. This example lists all the base table names in schema JDFCAT.T.
See chapter 10 of the SQL/MX reference manual for information on the metadata tables.
The table row counts are not stored in the system metadata, so you can't get them from there. For a table do SELECT ROW COUNT FROM TABLE;
SELECT
O.OBJECT_NAME
FROM
NONSTOP_SQLMX_SYSNAME.SYSTEM_SCHEMA.CATSYS C
INNER JOIN NONSTOP_SQLMX_SYSNAME.SYSTEM_SCHEMA.SCHEMATA S
ON (S.CAT_UID = C.CAT_UID)
INNER JOIN JDFCAT.DEFINITION_SCHEMA_VERSION_3600.OBJECTS O
on S.SCHEMA_UID = o.SCHEMA_UID
WHERE C.CAT_NAME = 'JDFCAT' AND
S.SCHEMA_NAME = 'T' AND
O.OBJECT_TYPE = 'BT'
READ UNCOMMITTED ACCESS;

How to phrase sql query when selecting second table based on information on first table

I have two tables I would like to call, but I am not sure if it is possible to combine them into one query or I have to some how call 2 different queries.
Basically I have 2 tables:
1) item_table: name/id etc. + category ID
2) category_table: categoryID, categoryName, categoryParentID.
The parent categories are also inside the same table with their own name.
I would like to call on my details from item_table, as well as getting the name of the category, as well as the NAME of the parent category.
I know how to get the item_table data, plus the categoryName through an INNER JOIN. But can I use the same query to get the categoryParent's name?
If not, what would be the mist efficient way to do it? The rest of the code is in C++.
SELECT item_table.item_name, c1.name AS CatName, c2.name AS ParentCatName
FROM item_table join category_table c1 on item_table.categoryID=c1.categoryID
LEFT OUTER JOIN category_table c2 ON c2.categoryID = c1.categoryParentID
SQL Fiddle: here

Counting and ordering entities over multiple relations

I have three tables with relations between;
Customer --> Order --> OrderLine
I want to know which customers placed orders with most order lines. Using pure SQL, I would go on using following query;
SELECT a.*, COUNT( c.id ) AS total FROM customer AS a
LEFT JOIN order AS b ON a.id = b.customer_id
LEFT JOIN order_line AS c ON b.id = c.order_id
GROUP BY a.id ORDER BY total DESC;
I saw another question here which I suspect could be the solution to my problem, but I can't really make sense of the answer to work over multiple relations.
This will get you the max order lines per customer:
from django.db.models import Max
custs = Customer.objects.annotate(max_order_lines=Max(order__orderline)).values('id', 'max_order_lines').order_by('-max_order_lines')
max_cust = custs[0]

Is it possible to convert into DQL or Doctrine Query Builder

I have 3 tables with column
A:
id
B:
id
a_id
C:
id
b.id
with native query:
SELECT a.id, b.id, c.id
FROM A as a
LEFT JOIN B as b
INNER JOIN C as c ON b.id = c.b_id
ON a.id = b.a_id
i have tried
SELECT a.id, b.id, c.id
FROM App\HomeBundle\Entity\A as a
LEFT JOIN App\HomeBundle\Entity\B as b
INNER JOIN App\HomeBundle\Entity\C as c
ON c.id = c.bId
ON a.id = b.aId
i got error:
Error: Expected Literal, got 'JOIN'
Is it possible to convert my native query to DQL or query builder? If possible, how it will be look like?
This is only a guess but too long for a comment. If I'm completely off base I'll delete this answer.
Assuming your native query is syntactically correct, perhaps MySQL is applying the last ON condition to the result of an INNER JOIN between b and c. If that's true, see if this gives you the same result:
SELECT a.id, b.id, c.id
FROM App\HomeBundle\Entity\A as a
LEFT JOIN (
SELECT bx.aID
FROM App\HomeBundle\Entity\B as bx
INNER JOIN App\HomeBundle\Entity\C as c
ON bx.id = c.bId
) b
ON a.id = b.aId
Note I corrected what I believe to be an error in your attempted solution (where you said ON c.id = c.bId).
This is an older question, but I believe you need to JOIN on the relationship, and not the entity.
For example, instead of
SELECT a
FROM Entity\A as a
LEFT JOIN Entity\B as b
It should be:
SELECT a
FROM Entity\A as a
LEFT JOIN a.entityB as b
If that is not clear, a.entityB is a property of the A entity, called "entityB". That property defines the relationship between A and B.
When you just JOIN entity to entity, Doctrine does not know how they are related. However, if you JOIN based on the property, Doctrine can use the annotations (or other mapping) to determine the relationship of A and B.
I've always had to use the WITH keyword instead of ON when using doctrine.

Doctrine2 Query Builder Left Join with Select

I want to implement this SQL using doctrine2 query builder:
SELECT c.*, COUNT(s.id) AS studentCount
FROM classes c
LEFT JOIN (
SELECT *
FROM student_classes
WHERE YEAR = '2012'
) sc ON c.id = sc.class_id
LEFT JOIN students s ON sc.student_id = s.id
GROUP BY c.id
I tried this one but didn't work
$qb = $this->getEntityManager()
->getRepository('Classes')
->createQueryBuilder('c');
$qb->select('c.id AS id, c.name AS name, COUNT(s) AS studentCount');
$qb->leftJoin(
$qb->select('sc1')
->from('StudentClasses', 'sc1')
->where('sc1.year = :year')
->setParameter('year', $inputYear),
'sc2'
);
$qb->leftJoin('sc2.students', 's');
$qb->groupBy('c.id');
return $qb->getQuery()->getScalarResult();
or should I use nativeSQL instead?
any help would be appreciated,
thanks.
What are you trying to do is really interesting, because JOIN on a SELECT seems to not be supported by Doctrine2 with DQL or QueryBuilder. Of course, you can try with a native query.
However, to answer to your question, I believe that you don't need to make a JOIN on a SELECT. Simply, JOIN on StudentClasses and then add a condition in the WHERE about the $year! The WHERE clause is made for that.
You can use WITH clause to join entity with additional check, For your subquery you can write the same using left join with year filter, In join part i have used c.studentClasses based on the assumption that in Classes entity you have some mapped property for StudentClasses entity
$qb = $this->getEntityManager()
->getRepository('Classes')
->createQueryBuilder('c');
$qb->select('c.id AS id, c.name AS name, COUNT(s) AS studentCount');
$qb->leftJoin('c.studentClasses','sc2', 'WITH', 'sc2.year = :year');
$qb->leftJoin('sc2.students', 's');
$qb->setParameter('year', $inputYear);
$qb->groupBy('c.id');