JCR query all nodes under a parent node - parent-child

I am trying to list, sort and paginate all folders and files under a parent node.This is my query selecting only folders and it gives me the expected result:
SELECT childFolder.[jcr:name], childFolder.[jcr:uuid] FROM [nt:base] AS parent LEFT OUTER JOIN [nt:folder] AS childFolder ON ISCHILDNODE(childFolder, parent) WHERE parent.[jcr:uuid] = 'a54ca11b-99f8-42cf-8348-8c0f3bc4f008' ORDER BY parent.[jcr:primaryType] DESC
Then I add another join for the files but it doesn't return any results:
LEFT OUTER JOIN [nt:file] AS childFile ON ISCHILDNODE(childFile, parent)
Final query:
SELECT childFolder.[jcr:uuid] FROM [nt:base] AS parent LEFT OUTER JOIN [nt:folder] AS childFolder ON ISCHILDNODE(childFolder, parent) WHERE parent.[jcr:uuid] = 'a54ca11b-99f8-42cf-8348-8c0f3bc4f008' ORDER BY parent.[jcr:primaryType] DESC
1.Is there any way to get folders and files with a single query?
2.In the first query I try to get [jcr:name] but it gives me null.How can I get the name of the nodes?

This one's working:
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:file]
UNION
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:folder]

Related

How to select specific properties of properties through DQL

I have the following Entities. First and foremost: the design derived from a legacy DB and it has been semplified here for clarity shake.
What I would like to do is selecting all the widgets along with their varsSelection populated (in this very moment Widget only contains PhyVarSelection instances so we can focus on them) which should have teir phyVar hydrated. Phyvar must not be populated with its ewCfgVar property.
I'm trying to do it by using DQL. I succeeded to select all the widgets and their relative varsSelection, but I'm not able to populate their relative phyVar. Is that possible? Here is the DQL I'm using:
$sql = <<<EOS
SELECT wid, partial phyvarsel.{id, phyVar, start}
FROM Belka\\TsBundle\\Entity\\Widget wid
LEFT JOIN Belka\\TsBundle\\Entity\\PhyVarSelection phyvarsel WITH wid.id = phyvarsel.widget
LEFT JOIN Belka\\TsBundle\\Entity\\PhyVar phyvar WITH phyvarsel.phyVar = phyvar.id
EOS;
$query = $this->getEntityManager()->createQuery($sql);
If I dump the result, Widget and varsSelection are correctly populated, but PhyVarSelection::phyVar is set to NULL.
The query DQL it generates is actually correct, and if I query it I get all the PhyVar's properties:
die(var_dump($query->getSQL()));
It generates:
SELECT a0_.id AS id0, a0_.title AS title1, a0_."order" AS order2, a0_.span_cols AS span_cols3, a0_.description AS description4, a1_.id AS id5, a1_.start AS start6, a2_.id AS id7, a0_.part_of_section AS part_of_section8, a1_.vartype AS vartype9, a1_.part_of_widget AS part_of_widget10, a1_.phy_var_sel AS phy_var_sel11, a2_.vartype AS vartype12, a2_.part_of_phy_meter AS part_of_phy_meter13, a2_.varname AS varname14, a2_.id_device AS id_device15 FROM app_t.widget a0_ LEFT JOIN app_t.var_selection a1_ ON (a0_.id = a1_.part_of_widget) AND a1_.vartype IN ('phy') LEFT JOIN app_t.variable a2_ ON (a1_.phy_var_sel = a2_.id) AND a2_.vartype IN ('phy');
I don't paste here the Entities' code but if you need it let me know with a comment below and I will update the question.
Update
I've also tried the following:
$sql2 = <<<EOS
SELECT phyvarsel, phyvar
FROM Belka\\TsBundle\\Entity\\PhyVarSelection phyvarsel
LEFT JOIN Belka\\TsBundle\\Entity\\PhyVar phyvar
WHERE phyvarsel.id = :phyvarselid
EOS;
$query2 = $this->getEntityManager()->createQuery($sql2);
$query2->setParameter('phyvarselid', '0');
$query2->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$varSel = $query2->getResult();
again, in this case I get PhyVarSelection but its attribute phyVar is still set to NULL.

SQLite left join with two conditions in right table

I have two tables: a list of items and the sort order scoped on some group_id.
Items belong either to a group or are common (group_id=0).
I want to query all common and group items with the correct sort order for this group. All items with sort order -1 must be dismissed. Items with no associated sort_order must be included.
Wrong (Naive) Query:
SELECT items.*
FROM items LEFT JOIN sort_order ON items._id = sort_order.item_id
WHERE (items.group_id=0 OR items.group_id=14)
AND sort_order.entity_id=14
AND sort_order.sort >= 0
Behaves like a inner join - items with no corresponding sort_order are dismissed.
Slow Query:
SELECT items.*
FROM items LEFT JOIN sort_order
ON items._id = sort_order.item_id AND sort_order.entity_id=14
WHERE (items.group_id=0 OR items.group_id=14)
AND sort_order.sort >= 0
With ~5.000 entries in sort_order and ~1500 items the query takes ~2 seconds.
My question: Is there a better/correct way to handle this?
Maybe nonsense:
SELECT items.* FROM items WHERE items.id not in (Select id from sort_order)
UNION
SELECT items.* FROM items INNER JOIN sort_order ON items._id = sort_order.item_id AND sort_order.entity_id=14 WHERE (items.group_id=0 OR items.group_id=14) AND sort_order.sort >= 0
Found the source of the slow query: I forgot to create an index containing both sort_order.item_id and sort_order.item_id.
Adding a combined index did the trick for me:
CREATE INDEX sort_order_item_group
ON sort_order (order_id, group_id);

How to reuse a table with UNION?

I am trying to reuse a table in SQLite. My attempt is as follows:
SELECT
Partials.e_sentence
FROM
(SELECT
e_sentence, _id
FROM
Pair
JOIN PairCategories
ON
_id=PairId AND CategoryId=53
UNION
SELECT
e_sentence, _id
FROM
Pair
WHERE
e_sentence LIKE '%' || 'how often' || '%'
GROUP BY
e_sentence)
AS Parents JOIN Partials
ON Parents._id=ParentId
UNION
SELECT
e_sentence
FROM
Parents
The key part I am trying to accomplish is at the bottom, where I try to UNION a table created in the previous statement. Is there a way to do this in SQLite, or am I forced to repeat the query that made the Parents table in the first half of the UNION?
In SQLite 3.8.3 or later, you can use a common table expression:
WITH Parents AS (
SELECT e_sentence, _id
FROM Pair
JOIN PairCategories
...
)
SELECT Partials.e_sentence
FROM Parents
JOIN Partials ON Parents._id = ParentId
UNION
SELECT e_sentence
FROM Parents;
If you're using an older SQLite (probably because you're using an older Android), you can create a view for the subquery:
CREATE VIEW Parents AS
SELECT e_sentence, _id
FROM Pair
JOIN PairCategories
...;
SELECT Partials.e_sentence
FROM Parents
JOIN Partials ON Parents._id = ParentId
UNION
SELECT e_sentence
FROM Parents;
If you do not want to have this view permanently in the database, you could make it temporary (CREATE TEMPORARY VIEW ...) so that it is not available outside the current database connection, or, as last resort, you could just insert the subquery wherever you would use Parent:
SELECT Partials.e_sentence
FROM (SELECT ...) AS Parents
JOIN Partials ON Parents._id = ParentId
UNION
SELECT e_sentence
FROM (SELECT ...) AS Parents;

Allowing additional data to be added after a join with blank rows

I've got a left join query that returns the correct number of rows (equal to the left table), but because the right table is empty, there are no corresponding rowid's. How can I add the rowid (RecNum should be the same value) to the empty table so that I can add data to the resulting dataset? Here's the query:
select
Week01.RecNum as RecNum,
Week01.UserName as UserName,
Week01.Day1Reg as Day1Reg,
Week01.Day1OT as Day1OT,
Week01.Day2Reg as Day2Reg,
Week01.Day2OT as Day2OT,
Week01.Day3Reg as Day3Reg,
Week01.Day3OT as Day3OT,
Week01.Day4Reg as Day4Reg,
Week01.Day4OT as Day4OT,
Week01.Day5Reg as Day5Reg,
Week01.Day5OT as Day5OT,
Week01.Day6Reg as Day6Reg,
Week01.Day6OT as Day6OT,
Week01.Day7Reg as Day7Reg,
Week01.Day7OT as Day7OT
from
"Project List"
left join
Week01
on
"Project List".RecNum = Week01.RecNum
and
Week01.UserName = "JustMe"
or, if that can't really be done, how about a query that will pre-create row entries in Week01 (if they don't already exist) to match the same RecNum column and fill in the username with "JustMe"? But, the thing is that if the RecNum already exists in Week01, it can't be overwritten. Any ideas on that? If that could be done, then the query above should work out just fine.
you can actually select it using IFNULL
SELECT
IFNULL(Week01.RecNum, "Project List".RecNum
..
To answer your question of getting all recNums that exists in project List but not in Week01
you can do use left join
select p.RecNum
from "Project List" p
left join Week01 w
on p.RecNum = w.RecNum
where w.RecNum is NULL
or you can use not exists clause
select p.RecNum
from "Project List" p
where not exists
( select 1 from Week01 w
where p.RecNum = w.RecNum
)

Sqlite double left outer join with count

I have the following DB structure:
tbl_record(_id,_id_user,...)
tbl_photo(_id,_id_record,...)
tbl_note(_id,_id_record,...)
When listing the records of a specific user while counting the number of photos a record has, I use the following query, which works fine:
SELECT tbl_record._id, COUNT(tbl_photo._id_record) AS photo_count FROM tbl_record
LEFT OUTER JOIN tbl_photo ON tbl_record._id=tbl_photo._id_record
WHERE tbl_record._id_user=? GROUP BY tbl_record._id;
Now, I'd like to do the same as above, but also count the number of notes a record has:
SELECT tbl_record._id, COUNT(tbl_photo._id_record) AS photo_count, COUNT(tbl_note._id_record) AS note_count FROM tbl_record
LEFT OUTER JOIN tbl_photo ON tbl_record._id=tbl_photo._id_record
LEFT OUTER JOIN tbl_note ON tbl_record._id=tbl_note._id_record
WHERE tbl_record._id_user=? GROUP BY tbl_record._id;
The count of the 2nd query does not work properly when a record has >0 photos & >0 notes, e.g. 3 photos & 5 photos which results in a count of 15 (3*5) for each.
Any idea how to make the 2nd query return the proper counts?
Thanks!!
You might be able to filter out duplicates by using COUNT(DISTINCT some_id), but this would be inefficient.
Better use correlated subqueries:
SELECT _id,
(SELECT COUNT(*)
FROM tbl_photo
WHERE _id_record = tbl_record._id
) AS photo_count,
(SELECT COUNT(*)
FROM tbl_note
WHERE _id_record = tbl_record._id
) AS note_count
FROM tbl_record
WHERE _id_user = ?

Resources