I've the following SQL Query which runs perfectly fine but now i want to calculate the count based on the following scenario:
SELECT d.vseverity, v.vulnstatus, v.vtitleid, d.vtitle
FROM vulnsummary v
JOIN project p ON v.projid = p.projid
AND v.stagename = p.currentstage
JOIN datasets d ON v.vtitleid = d.datasetid
The current Output is:
Now i want to show the count like this way:
High (Open) - 2
High (Closed) - 0
Medium (Open) - 1
Medium (Closed) - 0
Low (Open) - 3
Low (Closed) - 1
Please help me to solve this query, Thank You
You need to CROSS JOIN the distinct sets of severity and status values and then LEFT JOIN that to your table to allow you to count the values of each severity/status combination. Without sample data it's hard to be certain but something like this should work:
SELECT sv.vseverity, st.vulnstatus, COUNT(v.vseverity) AS count
FROM (
SELECT DISTINCT vseverity
FROM datasets
) sv
CROSS JOIN (
SELECT DISTINCT vulnstatus
FROM vulnsummary
) st
LEFT JOIN (
SELECT d.vseverity, v.vulnstatus
FROM vulnsummary v
JOIN project p ON v.projid = p.projid
AND v.stagename = p.currentstage
JOIN datasets d ON v.vtitleid = d.datasetid
) v ON v.vseverity = sv.vseverity AND v.vulnstatus = st.vulnstatus
GROUP BY sv.vseverity, st.vulnstatus
I don't have your full dataset, however, a RIGHT OUTER JOIN to a master volnstatus table will enable (the volnstatus table showing all options i.e. 'Open', 'Closed'). A rough draft example, with only the volnstatus table populated:
SELECT COUNT(s.vulnstatus) CountOf, t.vtype
FROM dbo.vusummary s
RIGHT OUTER JOIN
vusummarytype t
ON s.vulnstatus = t.vtype
GROUP BY t.vtype
Related
I coding web app for my client and have issue with selecting from database raports with newest revisions.
SELECT
raports.*,
r1.*,
users.*,
(SELECT COUNT(*) FROM changes WHERE changes.changes_raports_id = raports.raports_id) as changes,
(SELECT changes.changes_date FROM changes WHERE changes.changes_raports_id = raports.raports_id ORDER BY changes.changes_date DESC LIMIT 1) as last_change,
(SUM(injuries.injuries_min_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as min,
(SUM(injuries.injuries_max_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as max
FROM raports
LEFT JOIN users
ON users.users_id = raports.raports_users_id
LEFT JOIN changes
ON changes.changes_raports_id = raports.raports_id
LEFT JOIN raports_to_changes r1
ON r1.raports_to_changes_raports_id = raports.raports_id
LEFT JOIN injuries_to_raports
ON injuries_to_raports.injuries_to_raports_raports_id = r1.raports_to_changes_raports_id
LEFT JOIN injuries
ON injuries_to_raports.injuries_to_raports_injuries_id = injuries.injuries_id
WHERE r1.raports_to_changes_changes_id = (SELECT max(raports_to_changes_changes_id) FROM raports_to_changes r2 WHERE r2.raports_to_changes_raports_id = r1.raports_to_changes_raports_id)
GROUP BY raports.raports_id ORDER BY raports.raports_id ASC;
In columns max and min i have not correct average from injuries. When i checked it and count all injuries i had 36 when true number is 2 but i have 18 revisions. So is logic that i have looped COUNT with all revisions but i want only the newest
I try changing WHERE statements and more LEFT JOINs but nothing helped.
Could someone fixed that code?
Thank you in advanced
Based on the clues revealed by your queries, the data model may look like this:
The select list shows that you need:
users information of a reports_id
aggregated injuries_min_procent and injuries_max_procent at raports_id level. (see cte_raport_injuries)
number of changes of a raports_id (see cte_raport_changes)
the last change_date of a raports_id (see cte_raport_changes)
I'm not sure about the need for raports_of_changes based on information revealed in the question, so I'm going to ignore it for now.
with cte_raport_injuries as (
select r.raports_id,
sum(i.injuries_min_procent) / count(*) as injuries_min_procent,
sum(i.injuries_max_procent) / count(*) as injuries_max_procent
from raports r
join injuries_to_raports ir
on r.raports_id = ir.injuries_to_raports_raports_id
join injuries i
on ir.injuries_to_raports_injuries_id = i.injuries_id
group by r.raports_id),
cte_raport_changes as (
select r.raports_id,
count(c.changes_id) as changes,
max(c.changes_date) as last_change
from raports r
join changes c
on r.raports_id = c.changes_raports_id
group by r.raports_id)
select u.users_id,
r.raports_id,
ri.injuries_min_procent,
ri.injuries_max_procent,
rc.changes,
rc.last_change
from raports r
join users u
on r.raports_users_id = u.users_id
join cte_raport_injuries ri
on r.raports_id = ri.raports_id
join cte_raport_changes rc
on r.raports_id = rc.raports_id;
The result looks like this:
users_id|raports_id|injuries_min_procent|injuries_max_procent|changes|last_change|
--------+----------+--------------------+--------------------+-------+-----------+
1| 11| 15.0000| 25.0000| 2| 2022-12-02|
So my question for you is what's in reports_to_changes that you need and what's its relationship between others? For further involvement from the community, you may want to share the following information in text format:
DDLs of each tables (primary key, foreign key, column names & data types)
Some representable sample data and basic business rules
Expected output
I have four tables, three of which are pretty static: haul_types, dumpster_type_team (the dumpster_type_team has the many-to-many relationship between dumpster_types and teams), and users. The fourth table, hauls, has transactional data.
haul_types:
id
name
dumpster_type_team:
id
dumpster_type_id
team_id
users:
id
first_name
last_name
is_driver
team_id
hauls:
haul_type_id
haul_status_id
set_dumpster_type_id
completed_driver_id
team_id
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in. In some cases, there should be a count of zero because some drivers haven't completed hauls for every haul_type / dumpster type combination.
Here's the query I have so far that seems to be behaving as if it is an inner join because the records are getting filtered to only show where there are matches:
SELECT
c.haul_type_id,
c.dumpster_type_id,
c.driver_id,
count(h.id) AS haul_count
FROM
hauls h
RIGHT JOIN ( SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE) c ON c.haul_type_id = h.haul_type_id
AND c.dumpster_type_id = h.set_dumpster_type_id
AND c.driver_id = h.completed_driver_id
AND c.team_id = h.team_id
WHERE
h.team_id = 9
AND h.haul_status_id = 3
AND h.completed_driver_id IS NOT NULL
GROUP BY
c.haul_type_id, c.dumpster_type_id, c.driver_id
When I run the subquery in isolation:
SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE
I get the results I want: a row for each permutation of haul_type, dumpster_type, driver_id, and team_id. However, when I run the entire query, I get filtered results despite the right join.
What I would like to have is the following:
If I have 4 haul_types: delivery, swap, live, pickup
and 2 dumpster_types: 10YD, 15YD
and 2 drivers: 1, 2
I would like a haul count for the combination of haul_type, dumpster_type, and driver. If there are no hauls matching the row, show 0:
Any help is appreciated. Thank you
The description of the question and the query seem to have little to do with each other. I don't know what a "pivot table" is supposed to be.
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in.
This sounds like a cross join to generate the rows and then a left join/group by to calculate the results:
select d.dumpster_id, ht.haul_type_id, d.driver_id, count(h.driver_id)
from dumpster_types d cross join
haul_types ht cross join
drivers d left join
hauls h
on h.dumpster_id = d.dumpster_id and
h.haul_type_id = ht.haul_type_id and
h.driver_id = d.driver_id
group by d.dumpster_id, ht.haul_type_id, d.driver_id;
Running the query #GordonLinoff provided, exposed the issue I was facing - when applying a where clause on the top level query, the results were getting filtered to only matches. I moved the where clause to individual subqueries and now I am getting all expected results.
Not sure if this is the most efficient way to write it but it yields the correct results:
SELECT
d.dumpster_type_id,
ht.id AS haul_type_id,
u.id AS driver_id,
count(h.id) AS haul_count
FROM (
SELECT
dumpster_type_id,
team_id
FROM
dumpster_type_team
WHERE
team_id = 9) d
CROSS JOIN haul_types ht
CROSS JOIN (
SELECT
users.id
FROM
users
WHERE
users.is_driver = TRUE
AND users.team_id = 9) u
LEFT JOIN (
SELECT
id, set_dumpster_type_id, haul_type_id, completed_driver_id, team_id
FROM
hauls
WHERE
haul_status_id = 3
AND team_id = 9) h ON h.set_dumpster_type_id = d.dumpster_type_id
AND h.haul_type_id = ht.id
AND h.completed_driver_id = u.id
AND h.team_id = d.team_id
GROUP BY
d.dumpster_type_id,
ht.id,
u.id
I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state
Have an access report that shows training programs, and which employees should be but are not trained on that program. This query is fine. Problem is that we want to only display on the report training programs which have more than 10 employees untrained. So we have the total of untrained for each program in a subtotal, but we want to filter on that value.
How can this be done?
EDIT:
Here is pass-through query to SQL Server
SELECT T.ProgramTitle
,T.ProgramCode
,AE.Code AS 'AvantiCode'
,AE.FullName
,AE.FirstName
,AE.LastName
,AE.Department
,C.Position
,AE.Shift
FROM HR_Curriculum C
INNER JOIN HR_Trainings T ON C.TrainingID = T.TrainingID
INNER JOIN HR_EmployeeDetails ED ON C.Position = ED.Postion
INNER JOIN Avanti_Employees AE ON ED.AvantiRecID = AE.RecID
LEFT JOIN HR_Employeetrainings ET ON C.TrainingID = ET.TrainingID
AND ED.AvantiRecID = ET.AvantiRecID
LEFT JOIN HR_TrainingVersion V ON V.VersionID = ET.VersionID
WHERE terminated = 0
AND T.Active = - 1
AND CompletedDate IS NULL
GROUP BY T.ProgramTitle
,T.ProgramCode
,AE.Code
,AE.FullName
,AE.FirstName
,AE.LastName
,AE.Department
,C.Position
,AE.Shift
Order by programtitle
Consider an inline view, using a grouped by table alias with HAVING clause.
Try adding one more inner join:
INNER JOIN
(SELECT TrainingID, ProgramTitle, ProgramCode
FROM HR_Trainings
GROUP BY TrainingID, ProgramTitle, ProgramCode
HAVING Count(TrainingID) > 10) AS Trainings10More
ON Trainings10More.TrainingID = T.TrainingID
I currently have this working using a Sub-query, but as the DB grows this will become HUGELY inefficient. I'm wondering if there is a more efficient way to do what I need to do without sub-queries?
I need to have my final output look like so:
Question, Answer, Responses, Charts included in Response Count
Did this work?, N/A, 26, 30
Did this work?, Yes, 4, 30
This is my current query:
SELECT
bq_text,
ba_a,
bq_id,
COUNT(ba_a) AS ba_aC,
(SELECT COUNT(*) FROM board_done_sheet WHERE sd_b_id = bs.bs_id AND sd_sub = 1) AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
LEFT JOIN boardsubs bs
ON (bd.bd_b_id = bs.bs_id)
LEFT JOIN b_q_answers ba
ON (sh.sd_s_id = ba.ba_s_id)
LEFT JOIN bsquestions bq
ON (bq.bq_id = ba.ba_q_id)
LEFT JOIN multiples m
ON (ba.ba_m_id = m.m_id)
LEFT JOIN users u
ON (u.us_id = bd.bd_d_id)
LEFT JOIN profiles p
ON (p.p_u_id = bd.bd_d_id)
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
WHERE sd_sub = '1' AND bq_text <> 'Date' AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
That works perfectly, the problem is it has to use sub-queries which as time goes by will get less efficient.
I'm just wondering if there is a better more efficient way to do that summed field without it.
Presumably the subquery you're concerned about is the one in your toplevel SELECT.
That is easy to refactor so it won't get repeated.
Just JOIN it to the rest of the table. You'll want this sort of thing:
SELECT
bq_text, ...
COUNT(ba_a) AS ba_aC,
countup.countup AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
...
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
JOIN (
SELECT COUNT(*) AS countup , sd_b_id
FROM board_done_sheet
WHERE sd_sub = 1
GROUP BY sd_b_id
) AS countup ON countup.sd_b_id = bs.bs_id
WHERE sd_sub = '1'
AND bq_text <> 'Date'
AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
The countup subquery generates a summary table of counts and ids, and then joins it to the other tables.
A JOIN cascade of this complexity may become inefficient for other reasons as your table grows if you don't structure your indexes correctly.