ORACLE - How to count the total of two queries(with different WHERE clauses) from same table? - sql

I want to capture the aggregate of each number but am not sure how to gather all the results from a couple of queries(All data from the same table) that have different 'WHERE' criteria.
For example,
1st query:
SELECT * FROM tbl
WHERE tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF')
AND tbl.send_date > TRUNC(SYSDATE) - 30
GROUP BY tbl.job_nbr;
2nd query:
SELECT * FROM tbl
WHERE tbl.from IN ('GGGB','GVCE','GMWA','GTYR')
AND tbl.to IN ('GGGBP2','GVCEP3','GMWAP1','GTYRP3')
AND tbl.send_date > TRUNC(SYSDATE) - 30
GROUP BY tbl.job_nbr;
I'm not sure if just using a WHERE clause satisfy my requirement
WHERE tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF')
AND tbl.from IN ('GGGB','GVCE','GMWA','GTYR')
AND tbl.to IN ('GGGBP2','GVCEP3','GMWAP1','GTYRP3')
Where I get confused is that results that are produced by my 1st query don't need to meet the 1st AND operator condition of the 2nd query. It seems if I incorporate all of my listed values in the 'tbl.from IN' condition and use the AND operator('tbl.to IN') that the returned results will only be those listed in the 'tbl.from IN' condition with the 'tbl.to IN' column.
Both queries produce separate results obviously, but I want to combine set of results so that I can count all occurrences, GROUP'ed BY unique job number(tbl.job_nbr).
*Note: I'm a little concerned about performance as well, because I want to incorporated in a larger query.
I'm sure its something simple, or at least somewhat simple, but I've spent a lot of time trying to figure this out. If anyone would be kind enough help me out, I would greatly appreciate it!
If I did not explain clearly enough or anyone has additional questions, I'll do my best to clarify.

I think you want conditional aggregation:
SELECT tbl.job_nbr,
SUM(CASE WHEN tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF')
THEN 1 ELSE 0
END) as cnt1,
SUM(CASE WHEN tbl.from IN ('GGGB', 'GVCE', 'GMWA', 'GTYR') AND
AND tbl.to IN ('GGGBP2', 'GVCEP3', 'GMWAP1', 'GTYRP3')
THEN 1 ELSE 0
END) as cnt2
FROM tbl
WHERE tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF')
AND tbl.send_date > TRUNC(SYSDATE) - 30
GROUP BY tbl.job_nbr;

use case when, i mean conditional aggregation:
select tbl.job_nbr,
sum(case when tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF') then 1 else 0 end)
as firstquery_count,
sum(case when tbl.to IN ('GGGBP2','GVCEP3','GMWAP1','GTYRP3' then 1 else 0 end)
as secondndtquery_count
from tbl where tbl.send_date > TRUNC(SYSDATE) - 30
group by tbl.job_nbr
from comments it seems you want add both count so you can use cte
with cte as
(
select tbl.job_nbr,
sum(case when tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF') then 1 else 0 end)
as firstquery_count,
sum(case when tbl.to IN ('GGGBP2','GVCEP3','GMWAP1','GTYRP3' then 1 else 0 end)
as secondndtquery_count
from tbl where tbl.send_date > TRUNC(SYSDATE) - 30
group by tbl.job_nbr
) select job_nbr,firstquery_count+secondndtquery_count as total
from cte
but with using cte you could do the same with 1st query just by using addition of that two count

From what I understand you need 1 counter, so combine the conditions with OR:
SELECT tbl.job_nbr, COUNT(*) counter FROM tbl
WHERE
tbl.send_date > TRUNC(SYSDATE) - 30
AND
(
tbl.from IN ('NIVA', 'TIRB', 'RIFG', 'PWDF')
OR (
tbl.from IN ('GGGB','GVCE','GMWA','GTYR')
AND
tbl.to IN ('GGGBP2','GVCEP3','GMWAP1','GTYRP3')
)
)
GROUP BY tbl.job_nbr;

Related

Sum values in two different tables and join results keeping the columns

I have two tables: one with downtime and the other with productive time.
I want to have a table like this
But I am getting this
In the result, I am getting twice the downtime of the sum for the report 04102021-1, but as can be seen in the second picture, the value is present only once.
The script I am using is the following:
SELECT WAJ.REPORTCODE,--BASIC_REPORT_TABLE.TECHNICIAN,BASIC_REPORT_TABLE.JOBREPORTCODE,
SUM(CASE WHEN DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED)<0
THEN (86400+DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED))/3600.0
ELSE DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED) /3600.0
END) AS PRODUCTION_TIME,
SUM(CASE WHEN DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED)<0
THEN (86400+DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED))/3600.0
ELSE DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED) /3600.0
END) AS DOWNTIME
FROM WORK_AT_JOB WAJ,WAITING_AT_SITE WAS
WHERE (WAJ.REPORTCODE=WAS.REPORTCODE AND WAJ.REPORTCODE LIKE '04102021%') GROUP BY WAJ.REPORTCODE
After the #xQbert comment, I tried this:
SELECT WAS.REPORTCODE,
SUM(CASE WHEN DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED)<0
THEN (86400+DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED))/3600.0
ELSE DATEDIFF(SECOND,WAJ.TIMESTARTED,WAJ.TIMEFINISHED) /3600.0
END) AS PRODUCTION_TIME,
SUM(CASE WHEN DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED)<0
THEN (86400+DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED))/3600.0
ELSE DATEDIFF(SECOND,WAS.TIMESTARTED,WAS.TIMEFINISHED) /3600.0
END) AS DOWNTIME
FROM WAITING_AT_SITE WAS
JOIN WORK_AT_JOB WAJ
ON (WAJ.REPORTCODE=WAS.REPORTCODE AND WAS.REPORTCODE LIKE '04102021%') GROUP BY WAS.REPORTCODE
But I got the same result.
May you give some advice to get the result I want?
Thanks in advance
You could use conditional aggregation for this, but the easiest, and probably most performant, way to do this is to pre-aggregate the results before you join.
SELECT
waj.REPORTCODE
waj.PRODUCTION_TIME,
was.DOWNTIME
FROM (
SELECT
waj.REPORTCODE,
SUM(CASE WHEN v.diff < 0 THEN 86400 + v.diff ELSE v.diff END / 3600.0) AS PRODUCTION_TIME
FROM WORK_AT_JOB waj
CROSS APPLY (VALUES( DATEDIFF(SECOND, waj.TIMESTARTED, waj.TIMEFINISHED) )) v(diff)
WHERE waj.REPORTCODE LIKE '04102021%'
GROUP BY
waj.REPORTCODE
) waj
JOIN (
SELECT
was.REPORTCODE,
SUM(CASE WHEN v.diff < 0 THEN 86400 + v.diff ELSE v.diff END / 3600.0) AS PRODUCTION_TIME
FROM WAITING_AT_SITE was
CROSS APPLY (VALUES( DATEDIFF(SECOND, was.TIMESTARTED, was.TIMEFINISHED) )) v(diff)
WHERE was.REPORTCODE LIKE '04102021%'
GROUP BY
was.REPORTCODE
) was ON waj.REPORTCODE = was.REPORTCODE;
Note the use of CROSS APPLY (VALUES to avoid code repetition.

Multiple conditions in select statement based on values

I have a multiple ctes. In my select statement I must filter values base on the conditions. This is my query.
SELECT roadName
,sum(roadLength) AS sumRoadLength
,avg(elevationDifference) AS eglAvgDepth
,avg(elevationDifference) AS pglAvgDepth
,
FROM cte3
GROUP BY roadName
ORDER BY roadName
Under "elevationDifference" there are lots of values ranging from -10 to +20 which are spread through "roadName". What i want to accomplished is that "eglAvgDepth" will return if all "elevationDifference" values are <0 and take the average. Same case with pglAvgDepth where values are >0.
I tried to add where statement but works only in eglAvgDepth
WHERE elevationDifference < 0
GROUP BY roadName
ORDER BY roadName
Just add a conditional expression:
avg(case when elevationDifference < 0 then elevationDifference end) as eglAvgDepth,
avg(case when elevationDifference > 0 then elevationDifference end) as pglAvgDepth,
EDIT:
You have phrased this that you want the value based on whether all the values are positive or negative. If so:
(case when max(elevationDifference) < 0 then avg(elevationDifference) end) as eglAvgDepth,
(case when max(elevationDifference) > 0 then avg(elevationDifference) end) as pglAvgDepth,

Using SUM SEC_TO_TIME in MariaDB

Reference from How to sum time using mysql
I want to SUM Field LogsFormatted.Late Every month with query :
SELECT
SUM(CASE
WHEN MONTH (LogsFormatted.DateIn) = 1
THEN SEC_TO_TIME( SUM( TIME_TO_SEC(LogsFormatted.Late)))
ELSE 0 END
) AS '1'
FROM
HrAttLogsFormatted AS LogsFormatted
But the result is
1111 - Invalid use of group function
Where is the problem with the query? resulting in an error output.. Thank you in advance
[EDIT-SOLVED] It's Solved with simply apply
Change format SUM at the beginning of the query
SEC_TO_TIME(SUM(
CASE WHEN MONTH(LogsFormatted.DateIn) = 1 THEN
TIME_TO_SEC(LogsFormatted.Late) END)
) AS '1'
You don't need to call the sum() so many times. You can also move the case condition to the WHERE clause:
SELECT SUM(TIME_TO_SEC(lf.Late))
FROM HrAttLogsFormatted lf
WHERE MONTH(lf.DateIn) = 1 ;
If you want conditional aggregation, then do:
SELECT SUM(CASE WHEN MONTH(lf.DateIn) = 1 THEN TIME_TO_SEC(lf.Late) END)
FROM HrAttLogsFormatted lf;

SQL statement selecting a count of a column

I have this SQL query:
SELECT
COUNT(SDDOCO) AS Total
FROM
KAIPRDDTA.F4211LA, KAIPRDDTA.Dates
WHERE
SDDRQJ = Day10
which returns a count of all the orders for today.
I am trying to get a second column so that I have this:
To get orders that are not completed would be: SDNXTR < '562'. How would I add this to my sql query so that I can accomplish this goal? Let me know if you need anymore information and thanks in advance for your responses.
You have two options here:
SELECT
COUNT(SDDOCO) AS Total,
SUM(CASE WHEN SDNXTR < '562' THEN 1 ELSE 0 END) AS Not_Finished_Yet_With_SUM,
COUNT(CASE WHEN SDNXTR < '562' THEN 1 ELSE NULL END) AS Not_Finished_Yet_With_COUNT,
FROM
KAIPRDDTA.F4211LA, KAIPRDDTA.Dates
WHERE
SDDRQJ = Day10
You can use case statement to count that SDNXTR < '562' values like below:
SELECT count(SDDOCO) as Total,
sum(case when SDNXTR < '562' then 1 else 0 end) as not_yet_finished
FROM KAIPRDDTA.F4211LA, KAIPRDDTA.Dates
WHERE SDDRQJ = Day10

Alternative approach to multiple left joins

I have the following queries to count sales by route
SELECT DISTINCT q.sales_route,
y.yesterday,
t.today
FROM tblquotesnew q
left join (SELECT tblquotesnew.sales_route,
Count(tblquotesnew.sales_route) AS Yesterday
FROM tblquotesnew
WHERE tblquotesnew.date_sent_to_registrations =
Trunc(SYSDATE - 1)
AND sales_route IS NOT NULL
GROUP BY tblquotesnew.sales_route) y
ON q.sales_route = y.sales_route
left join (SELECT tblquotesnew.sales_route,
Count(tblquotesnew.sales_route) AS Today
FROM tblquotesnew
WHERE tblquotesnew.date_sent_to_registrations =
Trunc(SYSDATE)
AND sales_route IS NOT NULL
GROUP BY tblquotesnew.sales_route) t
ON q.sales_route = t.sales_route
I then have 6 other left joins to count current and previous week, month, and year.
This approach does work, but I was wondering if this is a more efficient (in terms of lines of code) way of pulling together this data?
I think you just need conditional aggregation:
select q.sales_route,
sum(case when q.date_sent_to_registrations = trunc(SYSDATE - 1)
then 1 else 0
end) as yesterday,
sum(case when q.date_sent_to_registrations = trunc(SYSDATE)
then 1 else 0
end) as today
from tblquotesnew q
group by sales_route
You may use conditional aggregation
SELECT sales_route,
sum(CASE WHEN date_sent_to_registrations = Trunc(SYSDATE)
AND sales_route IS NOT NULL
THEN 1 ELSE 0 END) today,
sum(CASE WHEN date_sent_to_registrations = Trunc(SYSDATE - 1)
AND sales_route IS NOT NULL
THEN 1 ELSE 0 END) yesterday
FROM tblquotesnew
GROUP BY sales_route
conditional aggregation leads to one sequential scan of your table which may be ok in many cases. An alternative solution is to use subqueries behind SELECT which may be sometimes more efficient. For example, if you access small subselect of data and you can create indexes to support it.