DQL - JOIN WITH properties of a relation - symfony

My question is similar to this, but different.
Can you join on a subquery with Doctrine 2 DQL?
I want to get all the rooms regardless, and left join any occupants who belong to a booking that exists on a given date.
For example (a plain mysql result set - doctrine would return objects):
Room ID | Occupant ID | Booking ID | Booking Start | Booking End
1 | 1 | 1 | Before today | After today
1 | 2 | 1 | Before today | After today
2 | NULL | NULL | NULL | NULL
Here's what I'm trying:
SELECT r, a, b
FROM MyBundle:Room r
LEFT JOIN r.occupants a
WITH a.booking is not null
LEFT JOIN a.booking b
WITH b.enrolmentStart <= :date
AND b.enrolmentEnd >= :date
AND b.status = 1
ORDER BY r.number ASC
Unfortunately, this gets all the rooms, with all the people who ever stayed in that room ever, but only the bookings that exist on that given date.
On the other hand, if I change to the following,
I'm given only rooms that have bookings on that given date.
LEFT JOIN r.occupants a
WITH a.booking is not null
JOIN a.booking b
If I try the following, Doctrine says it didn't expect a dot after the 'a'.
LEFT JOIN r.occupants a
WITH a.booking.enrolmentStart <= :date
AND a.booking.enrolmentEnd >= :date
AND a.booking.status = 1
LEFT JOIN a.booking b
And lastly, if I try the following, doctrine is not happy about the order.
LEFT JOIN r.occupants a
WITH b.enrolmentStart <= :date
AND b.enrolmentEnd >= :date
AND b.status = 1
LEFT JOIN a.booking b
Any ideas?

I think that you can achieve this query only using left joins:
SELECT
r.number, o.id_occupant, b.id_booking, b.enrolmentStart, b.enrolmentEnd
FROM
MyBundle:Room r
LEFT JOIN r.occupants o
LEFT JOIN o.booking b
AND b.status = 1
AND b.enrolmentEnd >= :date
AND b.enrolmentStart <= :date
ORDER BY r.number ASC
Take a look to this equivalent sql (SQL Fiddle) query.
Debugged sql:
select r.number, ref.id_occupant, ref.id_booking
from rooms r
LEFT JOIN (select * from rooms r2
left join occupants o on o.room = r2.id_room
left join booking b on b.id_booking = o.booking
where b.status = 1
and b.enrolmentEnd >= '2015/03/09'
and b.enrolmentStart <= '2015/03/10') as ref on r.id_room = ref.id_room

Related

HANA: Want to include offices that is having 0 value also

I have 4 offices in the table OFFICE_DETAILS which are a,b,c,d.
The below query outputs offices which are having any lab and rad count, so it is including all offices except for c
office_name lab_count rad_count
a 5 0
b 1 2
d 3 1
I want the output to be as follows:
office_name lab_count rad_count
a 5 0
b 1 2
c 0 0
d 3 1
what is the change required in the following code
SELECT d.OFFICE_name AS "OFFICE_NAME" ,
count(CASE
WHEN c.LAB_TYPE LIKE 'L' THEN 1
END) AS "LAB_TEST_COUNT",
count(CASE
WHEN c.LAB_TYPE in ('X','O') THEN 1
END) AS "RAD_TEST_COUNT"
FROM
DOCTOR_CONSULT a
INNER JOIN consult_labtest b
on(a.CONSULT_ID=b.CONSULT_ID)
INNER JOIN test_setup c
on(b.LABTEST_ID=c.TEST_ID)
INNER JOIN OFFICE_DETAILS d
on(a.OFFICE_ID=D.OFFICE_ID)
INNER JOIN USER_SETUP e
on(a.DOCTORS_ID = e.USER_ID)
INNER JOIN DEPARTMENT_SETUP f
ON(a.DEPARTMENT_ID = f.DEPARTMENT_ID)
INNER JOIN TEST_CATEGORY g
ON (c.CATEGORY_ID=g.CATEGORY_ID)
WHERE
c.LAB_TYPE IN ('L','X','O') --'L'-> Laboratory, 'X'-> Radiology
AND c.ACTIVE_STATUS='Y'
AND d.ACTIVE_STATUS='Y'
AND g.ACTIVE_STATUS='Y'
AND
a.CONSULT_DATE BETWEEN CURRENT_DATE AND CURRENT_DATE
AND
d.ACTIVE_STATUS='Y'
AND
a.EMPLOYEE_ID NOT IN ('NEW RECRUITMENT 380', '0000', 'army', 'undefined')
GROUP BY d.OFFICE_NAME
ORDER BY d.OFFICE_NAME ASC;
To retrieve result rows from joined tables that do not have matching rows (e.g. no matching entries in OFFICE_DETAILS table) SQL provides OUTER JOINS.
Join the details tables as outer joins and handle the resulting NULLs in the projection.
This is the most common approach to address this requirement.
Alternatively, the details tables could contain a special “no match” record that is used to match in an OR branch of the join condition. Some data warehouses do this to avoid NULLs.
I did by using LEFT JOIN. I am getting the required output
CREATE VIEW ECLINIC_KNG.VIEW_LABRADTESTS_OFFICE_COUNT_TODAY AS
SELECT ROW_NUMBER() OVER() AS row_num,
v1.OFFICE_NAME,
v1.LAB_TEST_COUNT,
v1.RAD_TEST_COUNT
FROM
(
SELECT od.OFFICE_NAME as "OFFICE_NAME",
(CASE WHEN v.LAB_TEST_COUNT IS NULL THEN 0 ELSE v.LAB_TEST_COUNT END) AS
"LAB_TEST_COUNT",
(CASE WHEN v.RAD_TEST_COUNT IS NULL THEN 0 ELSE v.RAD_TEST_COUNT END) AS
"RAD_TEST_COUNT"
FROM
OFFICE_DETAILS od
LEFT JOIN
(
SELECT d.OFFICE_NAME ,
count(CASE WHEN c.LAB_TYPE LIKE 'L' THEN 1 END) AS "LAB_TEST_COUNT",
count(CASE WHEN c.LAB_TYPE in ('X','O') THEN 1 END) AS "RAD_TEST_COUNT"
FROM
ECLINIC_KNG.DOCTOR_CONSULT a
INNER JOIN ECLINIC_KNG.consult_labtest b
on(a.CONSULT_ID=b.CONSULT_ID)
INNER JOIN ECLINIC_KNG.test_setup c
on(b.LABTEST_ID=c.TEST_ID)
INNER JOIN ECLINIC_KNG.OFFICE_DETAILS d
on(a.OFFICE_ID=D.OFFICE_ID)
INNER JOIN ECLINIC_KNG.USER_SETUP e
on(a.DOCTORS_ID = e.USER_ID)
INNER JOIN ECLINIC_KNG.DEPARTMENT_SETUP f
ON(a.DEPARTMENT_ID = f.DEPARTMENT_ID)
INNER JOIN ECLINIC_KNG.TEST_CATEGORY g
ON (c.CATEGORY_ID=g.CATEGORY_ID)
WHERE
c.LAB_TYPE IN ('L','X','O') --'L'-> Laboratory, 'X'-> Radiology
AND c.ACTIVE_STATUS='Y'
AND d.ACTIVE_STATUS='Y'
AND g.ACTIVE_STATUS='Y'
AND a.CONSULT_DATE BETWEEN CURRENT_DATE AND CURRENT_DATE
AND d.ACTIVE_STATUS='Y'
AND a.EMPLOYEE_ID NOT IN ('NEW RECRUITMENT 380', '0000', 'army', 'undefined')
GROUP BY d.OFFICE_NAME
ORDER BY d.OFFICE_NAME ASC
)AS v
on(od.OFFICE_NAME=v.OFFICE_NAME)
WHERE od.ACTIVE_STATUS='Y'
ORDER BY od.OFFICE_NAME
)AS v1

calculate percentages with postgresql join queries

I am trying to calculate percentages by joining 3 tables data to get the percentages of positive_count, negative_count, neutral_count of each user's tweets. I have succeeded in getting positive, negative and neutral counts, but failing to get the same as percentages instead of counts. Here is the query to get counts:
SELECT
t1.u_id,count() as total_tweets_count ,
(
SELECT count() from t1,t2,t3 c
WHERE
t1.u_id='18839785' AND
t1.u_id=t2.u_id AND
t2.ts_id=t3.ts_id AND
t3.sentiment='Positive'
) as pos_count ,
(
SELECT count() from t1,t2,t3
WHERE
t1.u_id='18839785' AND
t1.u_id=t2.u_id AND
t2.ts_id=t3.ts_id AND
t3.sentiment='Negative'
) as neg_count ,
(
SELECT count() from t1,t2,t3
WHERE
t1.u_id='18839785' AND
t1.u_id=t2.u_id AND
t2.ts_id=t3.ts_id AND
t3.sentiment='Neutral'
) as neu_count
FROM t1,t2,t3
WHERE
t1.u_id='18839785' AND
t1.u_id=t2.u_id AND
t2.ts_id=t3.ts_id
GROUP BY t1.u_id;
**OUTPUT:**
u_id | total_tweets_count | pos_count | neg_count | neu_count
-----------------+--------------------+-----------+-----------+-------
18839785| 88 | 38 | 25 | 25
(1 row)
Now I want the same in percentages instead of counts. I have written the query in the following way but failed.
SELECT
total_tweets_count,pos_count,
round((pos_count * 100.0) / total_tweets_count, 2) AS pos_per,neg_count,
round((neg_count * 100.0) / total_tweets_count, 2) AS neg_per,
neu_count, round((neu_count * 100.0) / total_tweets_count, 2) AS neu_per
FROM (
SELECT
count(*) as total_tweets_count,
count(
a.u_id='18839785' AND
a.u_id=b.u_id AND
b.ts_id=c.ts_id AND
c.sentiment='Positive'
) AS pos_count,
count(
a.u_id='18839785' AND
a.u_id=b.u_id AND
b.ts_id=c.ts_id AND
c.sentiment='Negative'
) AS neg_count,
count(
a.u_id='18839785' AND
a.u_id=b.u_id AND
b.ts_id=c.ts_id AND
c.sentiment='Neutral') AS neu_count
FROM t1,t2, t3
WHERE
a.u_id='18839785' AND
a.u_id=b.u_id AND
b.ts_id=c.ts_id
GROUP BY a.u_id
) sub;
Can anyone help me out in achieving as percentages for each user data as below?
u_id | total_tweets_count | pos_count | neg_count | neu_count
------------------+--------------------+-----------+-----------+-----
18839785| 88 | 43.18 | 28.4 | 28.4
(1 row)
I am not entirely sure what you are looking for.
For starters, you can simplify your query by using conditional aggregation instead of three scalar subqueries (which btw. do not need to repeat the where condition on a.u_id)
You state you want to "count for all users", so you need to remove the WHERE clause in the main query. The simplification also gets rid of the repeated WHERE condition.
select u_id,
total_tweets_count,
pos_count,
round((pos_count * 100.0) / total_tweets_count, 2) AS pos_per,
neg_count,
round((neg_count * 100.0) / total_tweets_count, 2) AS neg_per,
neu_cont,
round((neu_count * 100.0) / total_tweets_count, 2) AS neu_per
from (
SELECT
t1.u_id,
count(*) as total_tweets_count,
count(case when t3.sentiment='Positive' then 1 end) as pos_count,
count(case when t3.sentiment='Negative' then 1 end) as neg_count,
count(case when t3.sentiment='Neutral' then 1 end) as neu_count
FROM t1
JOIN t2 ON t1.u_id=t2.u_id
JOIN t3 t2.ts_id=t3.ts_id
-- no WHERE condition on the u_id here
GROUP BY t1.u_id
) t
Note that I replaced the outdated, ancient and fragile implicit joins in the WHERE clause with "modern" explicit JOIN operators
With a more up-do-date Postgres version, the expression count(case when t3.sentiment='Positive' then 1 end) as pos_count can also be re-written to:
count(*) filter (where t3.sentiment='Positive') as pos_count
which is a bit more readable (and understandable I think).
In your query you can achieve the repetition of the global WHERE condition on the u_id by using a co-related subquery, e.g.:
(
SELECT count(*)
FROM t1 inner_t1 --<< use different aliases than in the outer query
JOIN t2 inner_t2 ON inner_t2.u_id = inner_t1.u_id
JOIN t3 inner_t3 ON inner_t3.ts_id = inner_t2.ts_id
-- referencing the outer t1 removes the need to repeat the hardcoded ID
WHERE innter_t1.u_id = t1.u_id
) as pos_count
The repetition of the table t1 isn't necessary either, so the above could be re-written to:
(
SELECT count(*)
FROM t2 inner_t2
JOIN t3 inner_t3 ON inner_t3.ts_id = inner_t2.ts_id
WHERE inner_t2.u_id = t1.u_id --<< this references the outer t1 table
) as pos_count
But the version with conditional aggregation will still be a lot faster than using three scalar sub-queries (even if you remove the unnecessary repetition of the t1 table).

Find difference between tables where values differ

When I search for how to compare two tables in SQLite, and see what's differ, I mostly find answers like this:
SELECT B.id FROM B LEFT JOIN A ON B.id = A.id WHERE A.id IS NULL
and yes, it's correct if you want do find all the elements (or values for keys named 'id' in this case) in table B that is not in table A, i.e. all the new elements in B if B is a later version of A.
But what if I want to find all the id:s in B where the value for a certain key (or keys) deviate from the corresponding value in A? For example, if I have two tables, A and B with id:s and positions, and I want to get the result id=3 in this case, because it is the element in B that has a value that differ. What would be the easiest way to do that?
Table A Table B
id | x_value | y_value id | x_value | y_value
----------------------- -----------------------
1 | 29.9563 | 12.6764 1 | 29.9563 | 12.6764
2 | 45.5843 | 7.6733 2 | 45.5843 | 7.6733
3 | 28.2313 | 15.6579 3 | 39.2003 | 15.6579
Result:
id
--
3
You can do it with a inner join with your condition in the where clause.
select a.id
from tableA a join tableB b on a.id = b.id
where ifnull(a.x_value, 0) <> ifnull(b.x_value, 0)
or ifnull(a.y_value, 0) <> ifnull(b.y_value, 0)
You can use INTERSECT:
LiveDemo
SqlFiddleDemo
SELECT tA.id
FROM TableA tA
JOIN TableB tB
ON tA.id = tB.id
WHERE NOT EXISTS( SELECT tA.x_value, tA.y_value
INTERSECT
SELECT tB.x_value, tB.y_value);
I like this solution, because it is easy to extend. Just add new column names. No need to handle NULL manually.
I agree with shawnt00 that you can read the question that the goal was to find all the id:s where values have changed between the two tables AND id:s of new instances inserted to the second table. Here is the select-statement to accomplish that, if anyone is interested:
select b.id
from b left join a on b.id = a.id
where ifnull(a.x_value, 0) <> ifnull(b.x_value, 0)
or ifnull(a.y_value, 0) <> ifnull(b.y_value, 0)
or a.id is null;

Can't join two tables in sqlite

i have two tables:
CREATE TABLE "object_comment"
("object_id" INTEGER PRIMARY KEY NOT NULL,
"object_comment_text" TEXT,
"object_comment_title" TEXT,
"object_comment_date" DATETIME)
and
CREATE TABLE "object_comment_mark"
("object_id" INTEGER PRIMARY KEY DEFAULT null,
"object_comment_mark_value" FLOAT DEFAULT null,
"object_comment_mark_date" DATETIME DEFAULT null)
I need to join them with the object_id field but the unique rows should present in results too. (there are some equal object_id values which I need to join in one row and some object_id values are different but they should be in the result table)
Now I have this select query:
SELECT *
FROM object_comment
LEFT OUTER JOIN object_comment_mark ON object_comment.object_id = object_comment_mark.object_id
But in this case I don't have the rows from the second table where the object_id has unique value. Any help?
EDIT: what I need
object_comment
1 | bla-bla | first | 2013
2 | be-be | sec | 2014
object_comment_mark
1 | 5 | 2013
4 | 3 | 2013
result
1 |bla-bla | first| 2013 | 5 | 2013
2 | be-be | sec | 2014 | |
4 | | | | 3 | 2013
What you want is full outer join, which is not supported by SQLite.
Instead, you could combine a left join and the unmatched (NULL) records of a right join.
A right join isn't supported either, so use a left join with the two tables swapped:
SELECT oc.*, ocm.*
FROM object_comment AS oc
LEFT JOIN object_comment_mark AS ocm ON oc.object_id = ocm.object_id
UNION ALL
SELECT oc.*, ocm.*
FROM object_comment_mark AS ocm
LEFT JOIN object_comment AS oc ON oc.object_id = ocm.object_id
WHERE oc.object_id IS NULL
Alternatively, search for unmatched records by hand:
SELECT oc.*, ocm.*
FROM object_comment AS oc
LEFT JOIN object_comment_mark AS ocm ON oc.object_id = ocm.object_id
UNION ALL
SELECT NULL, NULL, NULL, NULL, *
FROM object_comment_mark
WHERE object_id NOT IN (SELECT object_id
FROM object_comment)
I'm not understanding exactly your question...
Is this you need?
SELECT * FROM object_comment
INNER JOIN object_comment_mark ON object_comment.object_id = object_comment_mark.object_id
UNION ALL
SELECT *, NULL, NULL, NULL, NULL FROM object_comment

SQLite Select data from multiple rows returned as one row

I would like to know whether it is possible to use a SELECT statement in SQLite to merge the data from two rows into one, similar to how is suggested in the SQL Server forum below.
Consider the scenario below which is based on SQL Server (taken from http://forums.aspfree.com/microsoft-sql-server-14/merge-the-two-rows-in-one-row-245550.html)
Given there is a table
Emp
ID | Name |
1 | x |
1 | P |
2 | y |
2 | Q |
3 | W |
We want the resulting data from the select statement to output:
Emp_Data
Id | Name-1 | Name-2 |
1 | x | P |
2 | y | Q |
3 | w | |
The answer in the post suggests the following SQL as a possible solution:
SELECT
a.ID,
[Name-1] = ISNULL((
SELECT TOP 1 Name
FROM emp
WHERE ID = a.ID),''),
[Name-2] = ISNULL((
SELECT TOP 1 b.Name
FROM emp b
WHERE b.ID = a.ID
AND Name NOT IN(
SELECT TOP 1 Name
FROM emp
WHERE ID = b.ID
)),'')
FROM emp a
GROUP BY a.ID
Using SQLite is it possible to generate the columns [Name-1] & [Name-2] using nested SELECT statements like we can do above in SQL Server?
SELECT
a.ID,
COALESCE(a.Name,'') as "Name-1",
COALESCE((SELECT b.Name FROM Emp b
WHERE b.ID = a.ID
AND b.rowid != a.rowid LIMIT 1),'') as "Name-2"
FROM emp a
GROUP BY a.ID
Doug's solution didn't work for me. The code below, however, did work for me but it's very slow...
SELECT
a.ID,
a.Name AS Name1,
(SELECT b.Name FROM Emp b
WHERE b.ID = a.ID
AND b.Name != a.Name LIMIT 1) AS Name2
FROM emp a
GROUP BY a.ID
try this:::
select id, group_concat(name) from emp group by id;
;)

Resources