Sql Query Output Join with another table - sql

I have a query which gives me the following output :
select
PD.ProductId, TotalCalls = COUNT(DISTINCT PD.LogId),
TrueCalls = COUNT(DISTINCT case when PD.ExceptionCode = ' ' then PD.LogId END),
ErrorCalls =COUNT(DISTINCT case when PD.ExceptionCode != ' ' then PD.LogId END),
PassPercentage = CONVERT(DECIMAL(10,1),100 - (CAST(COUNT(DISTINCT case when PD.ExceptionCode != ' ' then PD.LogId END) as float)/CAST(COUNT(PD.LogId) as float)*100))
from
Log P
INNER JOIN LogProduct PD ON P.LogId = PD.LogId
WHERE
(ResponseTime < '2013-09-28' and RequestTime > '2013-09-01')
Group By
PD.ProductId
It gives me the following output :
ProductId TotalCalls TrueCalls ErrorCalls PassPercentage
1 6 6 0 100.0
2 1 0 1 85.7
3 33 15 18 92.2
Now I have another Table :
Levels :
LevelId Min Max Bool ProductId
1 100 100 0 2
2 80 99 0 2
3 60 79 0 2
4 40 59 0 2
5 1 39 1 2
6 0 0 0 2
7 -1 -1 0 2
1 100 100 0 1
2 80 99 0 1
3 60 79 1 1
4 40 59 0 1
5 1 39 0 1
6 0 0 0 1
7 -1 -1 0 1
What I would like to do is compare the output of the first query and add a new LevelId column :
example :
I am looking for an output like this :
ProductId TotalCalls TrueCalls ErrorCalls PassPercentage LevelId
1 6 6 0 100.0 1
2 1 0 1 85.7 2
The logic here is that : I would like to compare the PassPercentage for each row for that particular product and find out which level it falls in .
In the example above : PassPercentage is 85.7 for product 2 . If you check the Levels table above for ProductId 2 ,
Level 2 should be chosen as 80 < 87.5 < 99
I cannot figure out How I can do this..
Please let me know how I go forward from here ... or give me ideas of what I ought to do ??

The query would look like
with stats as (
select
PD.ProductId, TotalCalls = COUNT(DISTINCT PD.LogId),
TrueCalls = COUNT(DISTINCT case when PD.ExceptionCode = ' ' then PD.LogId END),
ErrorCalls =COUNT(DISTINCT case when PD.ExceptionCode != ' ' then PD.LogId END),
PassPercentage = CONVERT(DECIMAL(10,1),100 - (CAST(COUNT(DISTINCT case when PD.ExceptionCode != ' ' then PD.LogId END) as float)/CAST(COUNT(PD.LogId) as float)*100))
from
Log P
INNER JOIN LogProduct PD ON P.LogId = PD.LogId
WHERE
(ResponseTime < '2013-09-28' and RequestTime > '2013-09-01')
Group By
PD.ProductId
)
select s.*, l.LevelId
from stats s
join levels l on l.ProductId = s.ProductId and s.PassPercentage between l.Min and l.Max

Related

How to select data with group by and subquery calculations?

I have two tables:
list_table:
id
name
1
a
2
b
3
c
vt_table:
id
list_id
amount
direction_id
1
1
20
1
2
1
12
2
3
1
15
1
4
2
23
1
5
1
20
1
6
1
20
2
7
1
18
1
I need this result:
amount (dir_id = 1 - dir_id = 2), list_id
amount
list_id
41
1
23
2
0
3
Amount is sum of all amount fields in table vt_table where direction_id = 1 minus sum of all amount fileds in table vt_table where direction_id = 2
And I need group this calculations by list_id, and if table have no rows with list_id 3, as example, amount must be 0.
I'm trying to do it with this query:
SELECT vt.list_id
, ((SELECT COALESCE(SUM(vt.amount), 0)
FROM table_name vt
WHERE vt.direction_id = 1)
-
(SELECT COALESCE(SUM(vt.amount), 0)
FROM table_name vt
WHERE direction_id = 2)) AS result
FROM table_name vt
GROUP BY vt.list_id
But I don't know how to group it correctly and make it so that if there were no entries for some list_id, then the amount was 0 for this list_id.
I use PostgreSQL 12.
Here the examples
You can try to use OUTER JOIN with condition aggregate function with COALESCE fucntion.
Query 1:
SELECT l.id,
SUM(COALESCE(CASE WHEN vt.direction_id = 1 THEN vt.amount END,0)) -
SUM(COALESCE(CASE WHEN vt.direction_id = 2 THEN vt.amount END,0)) AS result
FROM table_name vt
RIGHT JOIN list l ON vt.list_id = l.id
GROUP BY l.id
ORDER BY l.id
Results:
| id | result |
|----|--------|
| 1 | 41 |
| 2 | 23 |
| 3 | 0 |
Try something like this, as a start:
SELECT vt.list_id
, COALESCE(SUM(CASE WHEN direction_id = 1 THEN amount END), 0)
- COALESCE(SUM(CASE WHEN direction_id = 2 THEN amount END), 0) AS result
FROM table_name vt
GROUP BY vt.list_id
;
Result using your fiddle:
list_id
result
1
41
2
23
This just misses the cases where there are no vt rows for some list.
Use an outer join to address those cases.
SELECT SUM(CASE WHEN vt.direction_id = 1 THEN vt.amount ELSE 0 END) - SUM(CASE WHEN vt.direction_id = 2 THEN vt.amount ELSE 0 END) as amount,
lt.id as list_id
FROM list_table lt
LEFT OUTER JOIN vt_table vt
ON lt.id = vt.list_id
GROUP BY lt.id
ORDER BY lt.id

SQL Select with joins and calculate percentage

I have three tables and I'm trying to make a select statement to give me a result like the one below
Teams:
ID Name
1 A
2 B
3 C
Players:
ID Name TeamID
1 P1 1
2 P2 1
3 P3 2
Goals: (goaltype: H for home, A for away, T for training)
ID PID goaltype
1 1 A
2 1 A
3 1 H
4 2 A
5 2 H
6 3 A
7 3 T
Result will be Like:
Team totalGoals home away trainig percentage[(home/total)*100]
A 5 2 3 0 40%
B 2 0 1 1 0
C 0 0 0 0 0
This is my current query:
select t.name,
count(g.id) as totalGoals,
sum(case when g.GTYPE = 'H' then 1 else 0 end) as home,
sum(case when g.GTYPE = 'A' then 1 else 0 end) as away,
sum(case when g.GTYPE = 'T' then 1 else 0 end) as training,
--(home/totalGoals) as percentage
from teams t
left join players p on p.TeamID = t.id
left join goals g on g.pid = p.id
group by t.name
You can use conditional aggregation to get the results you want:
SELECT t.Name AS Team,
COUNT(g.goaltype) AS totalGoals,
SUM(CASE WHEN g.goaltype = 'H' THEN 1 ELSE 0 END) AS home,
SUM(CASE WHEN g.goaltype = 'A' THEN 1 ELSE 0 END) AS away,
SUM(CASE WHEN g.goaltype = 'T' THEN 1 ELSE 0 END) AS training,
CASE WHEN COUNT(g.goaltype) = 0 THEN 0
ELSE 100.0 * SUM(CASE WHEN g.goaltype = 'H' THEN 1 ELSE 0 END) /
COUNT(g.goaltype)
END AS percentage
FROM Teams t
LEFT JOIN Players p ON p.TeamID = t.ID
LEFT JOIN Goals g ON g.PID = p.ID
GROUP BY t.Name
ORDER BY t.Name
Output:
team totalgoals home away training percentage
A 5 2 3 0 40
B 2 0 1 1 0
C 0 0 0 0 0
Demo on SQLFiddle

How to modify a SQL SELECT request with GROUP BY

I'm using the following SQL request to Informix DB:
select fromQ, toQ, count(callid) as cont_num, type
from some_table
group by fromQ, toQ, type
order by fromQ, toQ;
It produces the result:
fromq toq cont_num type
-----------------------------------
Sales 12 1
English 1 1
MB 59 1
Reception 3 2
Reception 53 1
Service 1 1
MB Sales 1 1
MB English 1 1
This is OK, as expected. Please note there are 2 rows for toq=Reception.
Field WRTYPE can have values only from 1 to 3.
So idea is to make an output like this:
fromq toq cont_num type1 type2 type3
------------------------------------------------
Sales 12 12 0 0
English 1 1 0 0
MB 59 59 0 0
Reception 56 53 3 0
Service 1 1 0 0
MB Sales 1 1 0 0
MB English 1 1 0 0
Is there a simple way to do this?
Use conditional aggregation:
select fromQ, toQ, count(callid) as cont_num,
sum(case when type = 1 then 1 else 0 end) as type_1,
sum(case when type = 2 then 1 else 0 end) as type_2,
sum(case when type = 3 then 1 else 0 end) as type_3
from some_table
group by fromQ, toQ
order by fromQ, toQ;

Return only unique values

I'm trying to get counts of how many jobs were done, regardless of personnel working on them. What I need to do is filter out any duplicates, the catch is that the entire row isn't duplicate so DISTINCT won't work here. I want to filter out if there is any duplication based on JobCode, JobType TaskTime and day of week. So my table looks like the following:
JobCode JobType TaskTime EmployeeID M Tu W Th F Sa Su
==================================================================
1800 1 06:49 101 1 1 1 1 1 0 0
1800 1 06:49 102 1 0 0 0 0 0 0
1800 1 07:04 101 1 1 1 1 1 0 0
1800 1 07:26 101 1 1 1 1 1 0 0
1800 1 07:49 101 1 1 1 1 1 0 0
1800 2 15:55 101 1 1 1 1 1 0 0
1800 1 16:20 101 1 1 1 1 1 0 0
1800 1 16:50 101 1 1 1 1 1 0 0
1800 2 16:55 101 1 1 1 1 1 0 0
My SQL Query is like this
SELECT t1.JobCode, t1.JobType,
t1.M, t1.Tu, t1.W, t1.Th, t1.F, t1.Sa, t1.Su,
SUM(t1.M + t1.Tu + t1.W + t1.Th + t1.F + t1.Sa + t1.Su) as Totals
FROM Table1 AS t1
JOIN Table1 AS t1_overlap ON
t1_overlap.EmployeeID = t1.EmployeeID AND
t1_overlap.JobType = t1.JobType AND
t1_overlap.TaskTime = t1.TaskTime
AND
(
(t1.M = 1 AND t1_overlap.M = t1.M) OR
(t1.Tu = 1 AND t1_overlap.Tu = t1.Tu) OR
(t1.W = 1 AND t1_overlap.W = t1.W) OR
(t1.Th = 1 AND t1_overlap.Th = t1.Th) OR
(t1.F = 1 AND t1_overlap.F = t1.F) OR
(t1.Sa = 1 AND t1_overlap.Sa = t1.Sa) OR
(t1.Su = 1 AND t1_overlap.Su = t1.Su)
)
GROUP BY t1.JobCode, t1.JobType, t1.M, t1.Tu, t1.W, t1.Th, t1.F, t1.Sa, t1.Su
The data returned is like this
JobCode JobType M Tu W Th F Sa Su Totals
==================================================
1800 1 1 0 0 0 0 0 0 1
1800 1 1 1 1 1 1 0 0 30
1800 2 1 1 1 1 1 1 1 10
What I want to see is only unique values, so I don't want that first line that shows the job was worked on by employee 102 on only M because I'm already seeing that employee 101 worked on that same job on that same day and time. So what I want to see instead is the following:
JobCode JobType M Tu W Th F Sa Su Totals
==================================================
1800 1 1 1 1 1 1 0 0 30
1800 2 1 1 1 1 1 0 0 10
Really I don't need to see the days of the week, I'm just showing them here so I can see whats being returned. All I actually need to see for output is the JobCode, JobType and Totals like the following:
JobCode JobType Totals
======================
1800 1 30
1800 2 10
Help is greatly appreciated.
I think a quick subquery where you grab the max of each day, grouping by your key, then sum the results, would do the trick:
SELECT
jobcode,
jobtype,
sum(monday+tuesday+wednesday+thursday+friday+saturday+sunday) AS total
FROM
(
SELECT
jobcode,
jobtype,
tasktime,
max(m) as monday,
max(tu) as tuesday,
max(w) as wednesday,
max(th) as thursday,
max(f) as friday,
max(sa) as saturday,
max(su) as sunday
FROM Table1 T1
GROUP BY jobcode, jobtype, tasktime
) t2
GROUP BY jobcode, jobtype
There may be something more eloquent than that, but this should get the job done.
Try with the below query.
;With cte1
as
(SELECT ROW_NUMBER()OVER(PArtition by t1.JobCode,t1.JobType order by t1.JobCode,t1.JobType) RNO,t1.JobCode, t1.JobType,
SUM(t1.M + t1.Tu + t1.W + t1.Th + t1.F + t1.Sa + t1.Su) OVER(partition by t1.JobCode,t1.JobType ORDER BY t1.JobCode,t1.JobType ) as Totals
FROM Table1 AS t1
JOIN Table1 AS t1_overlap ON
t1_overlap.EmployeeID = t1.EmployeeID AND
t1_overlap.JobType = t1.JobType AND
t1_overlap.TaskTime = t1.TaskTime
AND
(
(t1.M = 1 AND t1_overlap.M = t1.M) OR
(t1.Tu = 1 AND t1_overlap.Tu = t1.Tu) OR
(t1.W = 1 AND t1_overlap.W = t1.W) OR
(t1.Th = 1 AND t1_overlap.Th = t1.Th) OR
(t1.F = 1 AND t1_overlap.F = t1.F) OR
(t1.Sa = 1 AND t1_overlap.Sa = t1.Sa) OR
(t1.Su = 1 AND t1_overlap.Su = t1.Su)
))
SELECT t1.JobCode, t1.JobType,Totals
FROM cte1
WHERE RNO=1
Basically, you can use the super-awesome ROW_NUMBER function and wrap the query so that you effectively 1) define a grouping, and 2) take ONLY the first row of each group. Look closely at the over (partition by ... order by ...) clause to understand how you can control the grouping and the "ranking" (which ones you want to make it through to the results).
select JobCode, JobType, Totals
from (
SELECT t1.JobCode, t1.JobType, SUM(t1.M + t1.Tu + t1.W + t1.Th + t1.F + t1.Sa + t1.Su) as Totals
,row_number() over (partition by t1.JobCode order by t1.JobType) as rseq
FROM Table1 AS t1
JOIN Table1 AS t1_overlap ON
t1_overlap.EmployeeID = t1.EmployeeID AND
t1_overlap.JobType = t1.JobType AND
t1_overlap.TaskTime = t1.TaskTime
AND
(
(t1.M = 1 AND t1_overlap.M = t1.M) OR
(t1.Tu = 1 AND t1_overlap.Tu = t1.Tu) OR
(t1.W = 1 AND t1_overlap.W = t1.W) OR
(t1.Th = 1 AND t1_overlap.Th = t1.Th) OR
(t1.F = 1 AND t1_overlap.F = t1.F) OR
(t1.Sa = 1 AND t1_overlap.Sa = t1.Sa) OR
(t1.Su = 1 AND t1_overlap.Su = t1.Su)
)
GROUP BY t1.JobCode, t1.JobType, t1.M, t1.Tu, t1.W, t1.Th, t1.F, t1.Sa, t1.Su
) x
where rseq = 1 --filter to keep only the "first" row (JobType) for each JobCode
Note that the comments about "how do you decide which one to keep" are valid, and this example assumes you want to see "one row per JobCode", and keep the "first JobType for that JobCode". This can be adjusted to fit, if you'll explain the logic you want to use a little more clearly.

how to double count column which already counted

Please help me to solve the problem
My real table is:
id group numberOfLevel(counted column)
1 10 4
2 10 2
3 11 2
4 11 1
5 11 3
6 11 2
7 21 1
8 21 2
9 30 1
10 40 2
But i want to show:
group 1st_level 2nd_level 3rd_level over4th_level
10 0 1 0 1
11 1 2 1 0
21 1 1 0 0
30 1 0 0 0
40 0 1 0 0
Which way do i need to use to show the table?
Please share experience ?
This is a basic pivot query, an ANSII SQL case expession can be used in such a query,
and it should work on most databases:
select group_nr,
sum( case when numberOfLevel = 1 then 1 else 0 end ) As level_1st,
sum( case when numberOfLevel = 2 then 1 else 0 end ) As level_2nd,
sum( case when numberOfLevel = 3 then 1 else 0 end ) As level_3rd,
sum( case when numberOfLevel >= 4 then 1 else 0 end ) As over4th_level
from table1
group by group_nr
;
demo: http://sqlfiddle.com/#!2/4bd04/4
Don't use group as a column name, because group is a keyword in SQL.