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

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

Related

How to use with statement in this query?

In this query, I want to use with-statement. I have a subquery that calculates A union all B and I want to use it with with-statement. But when I use with-statement I face the error that says "table or view does not exist".
what surprises me is when I replace the first part with with-statement it works correctly. But when I replace the second part, I face this error!!
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||''||deposit.CUSTOMER_NUM||'-
'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days
AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS
START_DATE,
MAIN_7.AMOUNT
AS TOTAL_AMOUNT,
MAIN_7.TRN_Count
AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(Active_Time_Table.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(Active_Time_Table.AMOUNT) AS AMOUNT,
Count(Active_Time_Table.AMOUNT) AS TRN_Count
from
(
Select F.DEPOSIT_KEY,
SUM (F.AMOUNT) AS TRN_AMOUNT,
MIN (F.EFFECTIVE_DATE) AS TRN_Start_DATE
from
(
A
union all
B
)F
Group by (F.DEPOSIT_KEY)
Having ( SUM (F.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and
Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
(
A
union all
B
)Active_Time_Table
on (Trans_Table.DEPOSIT_KEY = Active_Time_Table.DEPOSIT_KEY and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY ,
Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(Active_Time_Table.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
***********************************************************
with rep as
(A union all B)
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||'-
'||deposit.CUSTOMER_NUM||'-'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS START_DATE,
MAIN_7.AMOUNT AS TOTAL_AMOUNT,
MAIN_7.TRN_Count AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(rep.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(rep.AMOUNT) AS AMOUNT,
Count(rep.AMOUNT) AS TRN_Count
from
(
Select rep.DEPOSIT_KEY,
SUM (rep.AMOUNT) AS TRN_AMOUNT,
MIN (rep.EFFECTIVE_DATE) AS TRN_Start_DATE
from
rep
Group by (rep.DEPOSIT_KEY)
Having ( SUM (rep.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
rep rep
on (Trans_Table.DEPOSIT_KEY = rep.DEPOSIT_KEY and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY , Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(rep.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
That's a lot of code, but - to make it simple, I'd suggest you use WITH factoring clause as the first command, include all tables you use into it, and then - as the final SELECT - fetch data from all those CTEs. Something like this:
with
a as (select ... from ...),
b as (select ... from ...),
f as (select ... from ...),
...
select a.col1, b.col2, f.col3
from a join b on a.id = b.id
left join f on f.id = b.id
where ...

DQL - JOIN WITH properties of a relation

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

Proc sql to Pull data from different tables recursively

I need to perform a recursive count operation on tables but here are the challenges that I am facing with.
Lets say I have tables A, B, C, D, E, F, .... Z
Here is the code snippet of what I have,
Proc sql;
create table temp as(
select count(*)
from a
inner join b on a.id = b.id
inner join c on a.id = c.id
inner join d on a.id = d.id
where <condition>
);
Once this code is complete I need to run the same query with B, C, D and E and update the result in same temp table that I am trying to create. This way I have to do for the entire table list that I have.
Is there a recursive sql to do this. I don't require a separate macro to call the query each time with different tables.
I would not do it quite this way.
proc sql;
create table temp as (
select count(case when n(a.id,b.id,c.id,d.id)=4 then 1 else 0 end) as abcd_count,
count(case when n(b.id,c.id,d.id,e.id)=4 then 1 else 0 end) as bcde_count
from a outer join b on a.id=b.id
outer join c ... etc.
;
quit;
IE, just do one join and use case when... to determine what has the counts you need. Here I use n() to identify records with all 4 ids on them.

How to display 0 in count?

How can I display 0 if there is no qualification matching?
My current query is:
select s.sname, count(*) as number
from sailor s, boat b
where s.rating >= b.rating
group by s.sname
order by number desc;
And the result I got is:
a 3
b 3
c 2
However, it is not really what I am trying to achieve. I would like to display the result like this:
a 3
b 3
c 2
d 0
e 0
I try to change count() to isnull(count(), 0) or coalesce(count(*), 0) but it doesnt correct in this case.
CREATE TABLE sailor (
sname character varying primary key,
rating integer
);
create table boat (
bname character varying primary key,
color character varying,
rating integer
);
This may help you
select s.sname,(select count(*)
from boat b
where s.rating >= b.rating
) t
from sailor s
order by t desc;
SQLFIDDLE
You are using an inner join, which returns only rows when data in both tables matches.
To return sailors without any matching boat, use an outer join:
select s.sname, count(*) as number
from sailor s
left join boat b on s.rating >= b.rating
group by s.sname
order by number desc;

Get the most recent record for each user where value is 'K', action id is null or its state is 1

I have the following tables in SQL Server:
user_id, value, date, action_id
----------------------------------
1 A 1/3/2012 null
1 K 1/4/2012 null
1 B 1/5/2012 null
2 X 1/3/2012 null
2 K 1/4/2012 1
3 K 1/3/2012 null
3 L 1/4/2012 2
3 K 1/5/2012 3
4 K 1/3/2012 null
action_id, state
----------------------------------
1 0
2 1
3 1
4 0
5 1
I need to return the most recent record for each user where the value is 'K', the action id is either null or its state is set to 1. Here's the result set I want:
user_id, value, date, action_id
----------------------------------
3 K 1/5/2012 3
4 K 1/3/2012 null
For user_id 1, the most recent value is B and its action id is null, so I consider this the most recent record, but it's value is not K.
For user_id 2, the most recent value is K, but action id 1 has state 0, so I fallback to X, but X is not K.
user_id 3 and 4 are straightforward.
I'm interested in Linq to SQL query in ASP.NET, but for now T-SQL is fine too.
The SQL query would be :
Select Top 1 T1.* from Table1 T1
LEFT JOIN Table2 T2
ON T1.action_id = T2.action_id
Where T1.Value = 'K' AND (T1.action_id is null or T2.state = 1)
Order by T1.date desc
LINQ Query :
var result = context.Table1.Where(T1=> T1.Value == "K"
&& (T1.action_id == null ||
context.Table2
.Where(T2=>T2.State == 1)
.Select(T2 => T2.action_id).Contains(T1.action_id)))
.OrderByDescending(T => T.date)
.FirstOrDefault();
Good Luck !!
This query will return desired result set:
SELECT
*
FROM
(
SELECT
user_id
,value
,date
,action_id
,ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date DESC) RowNum
FROM
testtable
WHERE
value = 'K'
) testtable
WHERE
RowNum = 1
You can also try following approach if user_id and date combination is unique
Make sure to get the order of predicates in the join to be able to use indexes:
SELECT
testtable.*
FROM
(
SELECT
user_id
,MAX(date) LastDate
FROM
testtable
WHERE
value = 'K'
GROUP BY
user_id
) tblLastValue
INNER JOIN
testtable
ON
testtable.user_id = tblLastValue.user_id
AND
testtable.date = tblLastValue.LastDate
This would select the top entries for all users as described in your specification, as opposed to TOP 1 which just selects the most recent entry in the database. I'm assuming here that your tables are named users and actions:
WITH usersactions as
(SELECT
u.user_id,
u.value,
u.date,
u.action_id,
ROW NUMBER() OVER (PARTITION BY u.user_id ORDER BY u.date DESC, u.action_id DESC) as row
FROM users u
LEFT OUTER JOIN actions a ON u.action_id = a.action_id
WHERE
u.value = 'K' AND
(u.action_id IS NULL OR a.state = 1)
)
SELECT * FROM usersactions WHERE row = 1
Or if you don't want to use a CTE:
SELECT * FROM
(SELECT
u.user_id,
u.value,
u.date,
u.action_id,
ROW NUMBER() OVER (PARTITION BY u.user_id ORDER BY u.date DESC, u.action_id DESC) as row
FROM users u
LEFT OUTER JOIN actions a ON u.action_id = a.action_id
WHERE
u.value = 'K' AND
(u.action_id IS NULL OR a.state = 1)
) useractions
WHERE row = 1

Resources