How to select based on unnormalized column - sql

firstly sorry for vague title wasn't sure how to explain it. Loooking at the query below I want to pull incidents out where 'truck1' attended. Not just on its own but when other vehicles attended with it. Im sure its something straight forward but can't work it out.
select
i.incident_number
Vehicles,
countofvehicles
FROM
(
SELECT
i.Incident_Number,
array_agg(ir.RESOURCE) as vehicle,
count(ir.RESOURCE) as countofvehicles
FROM INCIDENT as i
JOIN RESOURCE as ir on i.Incident_Number = ir.Incident_Number
--WHERE ir. like '%Truck1%'
GROUP BY i.Incident_Number) i
Result
incident_Number vehicle countofvehicle
1 car1,car2,bike1 3
2 car1,car2,truck1 3
3 truck1 1
4 car1 1
If I wanted to see where only the incidents truck1 attended, using WHERE ir.RESOURCE like '%truck1% would only bring back incident number 3 and not incident 2 where it attended with other vehicles. How can I get around this please?
Thanks

You don't need a subquery for this, just a having clause:
SELECT i.Incident_Number,
array_agg(ir.RESOURCE) as vehicle,
count(ir.RESOURCE) as countofvehicles
FROM INCIDENT i JOIN
RESOURCE ir
ON i.Incident_Number = ir.Incident_Number
GROUP BY i.Incident_Number
HAVING SUM(CASE WHEN ir.RESOURCE like '%truck1% THEN 1 ELSE 0 END) > 1;
In fact, you probably don't need the join either, because the only field you are taking from INCIDENT is also in RESOURCE:
SELECT ir.Incident_Number,
array_agg(ir.RESOURCE) as vehicle,
count(ir.RESOURCE) as countofvehicles
FROM RESOURCE ir
GROUP BY ir.Incident_Number
HAVING SUM(CASE WHEN ir.RESOURCE like '%truck1% THEN 1 ELSE 0 END) > 1;

Related

count the number of times a combination of values occurs

Dataset looking at the types of crime for a given city.
Incident ID
Incident Code
Incident Category
Incident Subcategory
Incident Description
618691
4134
Assault
Simple Assault
Battery
618691
15300
Offences Against The Family And Children
Other
Hate Crime (secondary only)
618701
7053
Vehicle Impounded
Vehicle Impounded
Vehicle, Impounded
618701
65010
Traffic Violation Arrest
Traffic Violation Arrest
Traffic Violation Arrest
618701
65050
Other Miscellaneous
Other
Driving While Under The Influence Of Alcohol
626010
5043
Burglary
Burglary - Residential
Burglary, Residence, Unlawful Entry
626010
6381
Larceny Theft
Larceny Theft - Other
Embezzlement from Dependent or Elder Adult by Caretaker
626010
7041
Recovered Vehicle
Recovered Vehicle
Vehicle, Recovered, Auto
626010
16650
Drug Offense
Drug Violation
Methamphetamine Offense
Each IncidentID has 2, 3, or 4 Incident Codes associated with it.
I want to be able to count the number of times each combination of 2, 3, or 4 Incident Codes appears in the entire dataset.
For example:
Incident Codes 4134, 15300: x amount of times
Incident Codes 7053, 65010, 65050: x amount of times
Incident Codes 5043, 6381, 7041, 16650: x amount of times
I apologize if I've given a poor explanation - this is my first post on SO and quite frankly I don't know how to best communicate this question.
I don't know what SQL code to run to get my answer. The closest I've come to finding an answer is this post, Select combination of two columns, and count occurrences of this combination, but it already has the data separated into two columns, which my data is not there.
My thought is to split the additional codes into other columns, but perhaps there is a way to avoid doing that by having the code run the calculation for me without it.
I appreciate any and all input you may be able to give!
Let's suppose your table is named "TableX". I think this query should be near to what you need:
Select T1.IncidentCode, T2.IncidentCode, T3.IncidentCode, T4.IncidentCode, Count(1) AS AmountOfTimes
From TableX T1
Join TableX T2 ON T2.IncidentID = T1.IncidentID AND
T2.IncidentCode <> T1.IncidentCode
Left Join TableX T3 ON T3.IncidentID = T1.IncidentID AND
T3.IncidentCode <> T1.IncidentCode AND
T3.IncidentCode <> T2.IncidentCode
Left Join TableX T4 ON T4.IncidentID = T1.IncidentID AND
T4.IncidentCode <> T1.IncidentCode AND
T4.IncidentCode <> T2.IncidentCode AND
T4.IncidentCode <> T3.IncidentCode
Group By T1.IncidentCode, T2.IncidentCode, T3.IncidentCode, T4.IncidentCode
You would probably be best to try and NOT get all 3 parts in one query and here is why. Lets say for example that one officer enters their data as codes 1, 2, 3. Another enters codes as 3, 1, 2, and yet another enters as 2, 3, 1. They are all the same "set" of codes just in different order. If you rely on just being the first being the same, you would be getting 3 different rows showing the same thing each with 1 count.
You would be better served by running 3 distinct queries with a WHERE and HAVING clause based on just the codes you are interested in the "set". Something simple like
select
YT.IncidentID,
count(*) HowMany
from
YourTable YT
where
YT.IncidentCode in ( 4134, 15300 )
group by
YT.IncidentID
having
count(*) = 2
This will return all incidents that have BOTH parts, even if the incident was associated with any 3rd and/or 4th additional codes in a given incident. Having the total records IS your count.
So, now, take your codes of interest ex: 1 & 2, and you have the possibility of 2 more incident codes per incident, and you add an additional 30+ combinations of codes 3 & 4 into the mix. If you dont care about the others that may be "extra", it does not screw up your count on the precise piece(s) you are looking for.
Then, all you have to do to get your other "what if" scenario counts is change your IN clause once and the having to match the count. Since you are only filtering based on the specific codes in question, you only want those that have the same count regardless of extra incident codes per example stated.
YT.IncidentCode in ( 7053, 65010, 65050 )
group by
YT.IncidentID
having
count(*) = 3
YT.IncidentCode in ( 5043, 6381, 7041, 16650 )
group by
YT.IncidentID
having
count(*) = 4
Now, if you only really care about the final count of each respectively, just wrap that up one more to get the count of rows returned such as
select
count(*) NumberOfIncidents
from
( select
YT.IncidentID,
count(*) HowMany
from
YourTable YT
where
YT.IncidentCode in ( 4134, 15300 )
group by
YT.IncidentID
having
count(*) = 2 ) PreQualified
Then, if you wanted to do this on some time period basis such as you have a given date of the incident, and you wanted to keep running the same query / counts, you could expand and do something like this by doing a UNION to each query.
select
'Assault and Offenses against Family and Children' as Activity,
count(*) NumberOfIncidents
from
( select
YT.IncidentID,
count(*) HowMany
from
YourTable YT
where
YT.IncidentCode in ( 4134, 15300 )
AND WhateverDateFilters...
group by
YT.IncidentID
having
count(*) = 2 ) PreQualified
UNION
select
'Vehicle Impound, Traffic Arrest, Other Misc' as Activity,
count(*) NumberOfIncidents
from
( select
YT.IncidentID,
count(*) HowMany
from
YourTable YT
where
YT.IncidentCode in ( 7053, 65010, 65050 )
AND WhateverDateFilters...
group by
YT.IncidentID
having
count(*) = 3 ) PreQualified
UNION
select
'Burglary, Theft, Drugs and Vehicle Recovery' as Activity,
count(*) NumberOfIncidents
from
( select
YT.IncidentID,
count(*) HowMany
from
YourTable YT
where
YT.IncidentCode in ( 5043, 6381, 7041, 16650 )
AND WhateverDateFilters...
group by
YT.IncidentID
having
count(*) = 4 ) PreQualified
Notice each query in the UNION returns the same number, and order of columns. So it will just return a list (in this case) of 3 rows with a description and count per category regardless of the physical order the incident codes were entered, even IF they were entered in the 3rd and 4th when only looking for 2 code possibilities.
Sometimes a generic query (as in the left-join sample) is ok, and nothing wrong with it, but ask yourself the flexibility and do you want to drill into each permutation just to get your final result numbers.

select sum where condition is true and count > 3

I have two tables.
FootballPlayers with columns Id_footballplayer, Last_Name, Fisrt_Name, Age
Transfers with columns Id_transfer, Name_club, price, date, acceptance (yes or no), code_footballplayer
How can I write a SQL query to select the last names of the players and the sum of the successful transfers carried out by them, the number of which exceeds 3?
I already wrote a query that displays the total amount of all successful transfers for each player
SELECT FootballPLayers.Last_Name,
SUM(CASE acceptance WHEN 'yes' THEN price ELSE 0 END) AS amount_price
FROM FootballPlayers
INNER JOIN Transfers ON FootballPlayers.ID_footballplayer = Transfers.code_footballplayer
GROUP BY FootballPlayers.Last_Name;
But I don’t know how to add a condition if the number of successful transfers is more than 3
Since this is a group scenario, after theGROUP BY you probably want:
HAVING COUNT(1) > 3
The HAVING clause works very similarly to WHERE, but is applied differently.
An alternative would be the sub-query:
SELECT * FROM
(
SELECT FootballPLayers.Last_Name,
SUM(CASE acceptance WHEN 'yes' THEN price ELSE 0 END) AS amount_price,
COUNT(1) AS [Transfers]
FROM FootballPlayers
INNER JOIN Transfers ON FootballPlayers.ID_footballplayer = Transfers.code_footballplayer
GROUP BY FootballPlayers.Last_Name
) x
WHERE x.Transfers > 3

Is there a way to get sql to output information arranged by month while showing a percentage for each month?

This outputs two columns. First is number of incidents, second is a 1 or 0 for breached or not breached. I'm trying to see if there's a way to show this data arranged by month with a percentage of breached vs not breached.
SELECT TOP 5000
[incidents] = Count(task_sla.dv_sla),
task_sla.has_breached,
resolved_at
FROM
incident
left join task_sla
on incident.number = task_sla.dv_task
WHERE
dv_task like 'INC%'
and dv_sla like 'Resolution%'
GROUP BY
task_sla.has_breached,
resolved_at
I think you want something like this:
SELECT YEAR(i.date), MONTH(i.date),
COUNT(*) as num_incidents,
AVG(CASE WHEN t.has_breached = 1 THEN 1.0 ELSE 0 END) as ratio_breached
FROM incident i left join
task_sla t
on i.number = t.dv_task and
t.dv_task like 'INC%'
WHERE ?.dv_sla like 'Resolution%'
GROUP BY YEAR(i.date), MONTH(i.date)
ORDER BY YEAR(i.date), MONTH(i.date);

Using Count case

So I've been just re-familiarizing myself with SQL after some time away from it, and I am using Mode Analytics sample Data warehouse, where they have a dataset for SF police calls in 2014.
For reference, it's set up as this:
incident_num, category, descript, day_of_week, date, time, pd_district, Resolution, address, ID
What I am trying to do is figure out the total number of incidents for a category, and a new column of all the people who have been arrested. Ideally looking something like this
Category, Total_Incidents, Arrested
-------------------------------------
Battery 10 4
Murder 200 5
Something like that..
So far I've been trying this out:
SELECT category, COUNT (Resolution) AS Total_Incidents, (
Select COUNT (resolution)
from tutorial.sf_crime_incidents_2014_01
where Resolution like '%ARREST%') AS Arrested
from tutorial.sf_crime_incidents_2014_01
group by 1
order by 2 desc
That returns the total amount of incidents correctly, but for the Arrested, it keeps printing out 9014 Arrest
Any idea what I am doing wrong?
The subquery is not correlated. It just selects the count of all rows. Add a condition, that checks for the category to be equal to that of the outer query.
SELECT o.category,
count(o.resolution) total_incidents,
(SELECT count(i.resolution)
FROM tutorial.sf_crime_incidents_2014_01 i
WHERE i.resolution LIKE '%ARREST%'
AND i.category = o.category) arrested
FROM tutorial.sf_crime_incidents_2014_01 o
GROUP BY 1
You could use this:
SELECT category,
COUNT(Resolution) AS Total_Incidents,
SUM(CASE WHEN Resolution LIKE '%ARREST%' THEN 1 END) AS Arrested
FROM tutorial.sf_crime_incidents_2014_01
GROUP BY category
ORDER BY 2 DESC;

General report of couple tables with inner joins

I need to create a general report about of a trucks in a company.
I have this tables in my schema:
Schema image:
Basically, I need to create a table containing the following:
|Location|Trucks|TotalOfCampaings|CampaingsWithCompleteStatus|CampaingsWithInProcessStatus|
Location: Location of the trucks, are in the Truck table.
Trucks: Number of Trucks by Location.
TotalOfCampaings: Total Number of Campaings by the Location and Trucks.
CampaingsWithCompleteStatus: Total Number of Campaings Completed, the status are in the table Campaing Control.
CampaingsWithInProcessStatus: Total Number of Campaings not finished.
Campaing = Order to fix one or multiple trucks.
I tried with a inner joins querys, but i cant get what i expect for the general report.
I would appreciate help me with this!
SELECT *
FROM
-- Prepare the base data for the report
(SELECT location, COUNT(*) AS Trucks FROM Truck GROUP BY location) loc
-- The statistics needed, make sure it is 1 to 1
-- The status value just guess as you did not mention in the question
OUTER APPLY
(
SELECT
COUNT(*) AS TotalOfCampaings,
SUM(CASE WHEN cc.campaing_status = 'Complete' THEN 1 ELSE 0 END) AS CampaingsWithCompleteStatus,
SUM(CASE WHEN cc.campaing_status = 'InProcess' THEN 1 ELSE 0 END) AS CampaingsWithInProcessStatus
FROM CampaingControl cc INNER JOIN Truck t ON cc.vin = t.vin
WHERE t.location = loc.location
) stat