INNER JOIN and COUNT in the same query - sql

I am having trouble with putting together INNER JOIN and COUNT in the same query.
Tables are:
TABLE STREETS
ID | STREET_NAME
------------------------
1 | Elm street
2 | Some other street
3 | Unknown street
4 | Killer street
5 | Dead-end street
TABLE ACCIDENTS_STREETS
STREET_ID | ACCIDENT_ID
-----------------------
2 | 4
2 | 7
2 | 2
2 | 1
5 | 3
I would like to get the street name where most accidents have occured.
This is for COUNT:
SELECT TOP 1 COUNT(STREET_ID) AS dangerous_street FROM ACCIDENTS_STREETS GROUP BY STREET_ID ORDER BY dangerous_street DESC
How to add INNER JOIN there to get only the name of the street?
Any advice is appreciated!

The Following should work
SELECT TOP 1 S.STREET_NAME,COUNT(a.*) AS dangerous_street
FROM ACCIDENTS_STREETS A
inner Join STREET S on S.ID = A.STREET_ID
GROUP BY S.STREET_NAME ORDER BY dangerous_street DESC

try this...
After joining the streets table, you would have to use an aggregation function to get the name in the resultset
SELECT
TOP 1 COUNT(STREET_ID) AS dangerous_street
, min( STREET_NAME) dangerous_STREET_NAME
FROM ACCIDENTS_STREETS acc
inner join STREETS str
on acc.STREET_ID=str.id
GROUP BY STREET_ID
ORDER BY dangerous_street DESC

Related

SQL server matching two table on a column

I have two tables one storing user skills another storing skills required for a job. I want to match how many skills a of each user matches with a job.
The table structure is
Table1: User_Skills
| ID | User_ID | Skill |
---------------------------
| 1 | 1 | .Net |
---------------------------
| 2 | 1 | Software|
---------------------------
| 3 | 1 | Engineer|
---------------------------
| 4 | 2 | .Net |
---------------------------
| 5 | 2 | Software|
---------------------------
Table2: Job_Skills_Requirement
| ID | Job_ID | Skill |
--------------------------
| 1 | 1 | .Net |
---------------------------
| 2 | 1 | Engineer|
---------------------------
| 3 | 1 | HTML |
---------------------------
| 4 | 2 | Software|
---------------------------
| 5 | 2 | HTML |
---------------------------
I was trying to have comma separated skills and compare but these can be in different order.
Edit
All the answers here are excellent. The result I am looking for is matching all jobs with all users as later on I will match other properties as well.
You could join the tables by the skill columns and count the matches:
SELECT user_id, job_id, COUNT(*) AS matching_skills
FROM user_skills u
JOIN job_skills_requirement j ON u.skill = j.skill
GROUP BY user_id, job_id
EDIT:
IF you want to also show users and jobs that have no matching skills, you can use a full outer join instead.
SELECT user_id, job_id, COUNT(*) AS matching_skills
FROM user_skills u
FULL OUTER JOIN job_skills_requirement j ON u.skill = j.skill
GROUP BY user_id, job_id
EDIT 2:
As Jiri Tousek commented, the above query will produce nulls where there's no match between a user and a job. If you want a full Cartesian products between them, you could use (abuse?) the cross join syntax and count how many skills actually match between each user and each job:
SELECT user_id,
job_id,
COUNT(CASE WHEN u.skill = j.skill THEN 1 END) AS matching_skills
FROM user_skills u
CROSS JOIN job_skills_requirement j
GROUP BY user_id, job_id
If you want to match all users and all jobs, then Mureinik's otherwise excellent answer is not correct.
You need to generate all the rows first, which I would do using a cross join and then count the matching ones:
select u.user_id, j.job_id, count(jsr.job_id) as skills_in_common
from users u cross join
jobs j left join
user_skills us
on us.user_id = u.user_id left join
Job_Skills_Requirement jsr
on jsr.job_id = j.job_id and
jsr.skill = us.skill
group by u.user_id, j.job_id;
Note: This assumes the existence of a users and a jobs table. You can of course generate these using subqueries.
WITH User_Skills(ID,User_ID,Skill)AS(
SELECT 1,1,'.Net' UNION ALL
SELECT 2,1,'Software' UNION ALL
SELECT 3,1,'Engineer' UNION ALL
SELECT 4,2,'.Net' UNION ALL
SELECT 5,2 ,'Software'
),Job_Skills_Requirement(ID,Job_ID,Skill)AS(
SELECT 1,1,'.Net' UNION ALL
SELECT 2,1,'Engineer' UNION ALL
SELECT 3,1,'HTML' UNION ALL
SELECT 4,2,'Software' UNION ALL
SELECT 5,2 ,'HTML'
),Job_User_Skill AS (
SELECT j.Job_ID,u.User_ID,u.Skill
FROM Job_Skills_Requirement AS j INNER JOIN User_Skills AS u ON u.Skill=j.Skill
)
SELECT jus.Job_ID,jus.User_ID,COUNT(jus.Skill),STUFF(c.Skills,1,1,'') AS Skill
FROM Job_User_Skill AS jus
CROSS APPLY(SELECT ','+j.Skill FROM Job_User_Skill AS j WHERE j.Job_ID=jus.Job_ID AND j.User_ID=jus.User_ID FOR XML PATH('')) c(Skills)
GROUP BY jus.Job_ID,jus.User_ID,c.Skills
ORDER BY jus.Job_ID
Job_ID User_ID Skill
----------- ----------- ----------- -------------
1 1 2 .Net,Engineer
1 2 1 .Net
2 1 1 Software
2 2 1 Software

Count how many times a value appears in tables SQL

Here's the situation:
So, in my database, a person is "responsible" for job X and "linked" to job Y. What I want is a query that returns: name of person, his ID and he number of jobs it's linked/responsible. So far I got this:
select id_job, count(id_job) number_jobs
from
(
select responsible.id
from responsible
union all
select linked.id
from linked
GROUP BY id
) id_job
GROUP BY id_job
And it returns a table with id in the first column and number of occurrences in the second. Now, what I can't do is associate the name of person to the table. When i put that in the "select" from beginning it gives me all the possible combinations... How can I solve this? Thanks in advance!
Example data and desirable output:
| Person |
id | name
1 | John
2 | Francis
3 | Chuck
4 | Anthony
| Responsible |
process_no | id
100 | 2
200 | 2
300 | 1
400 | 4
| Linked |
process_no | id
101 | 4
201 | 1
301 | 1
401 | 2
OUTPUT:
| OUTPUT |
id | name | number_jobs
1 | John | 3
2 | Francis | 3
3 | Chuck | 0
4 | Anthony | 2
Try this way
select prs.id, prs.name, count(*) from Person prs
join(select process_no, id
from Responsible res
Union all
select process_no, id
from Linked lin ) a on a.id=prs.id
group by prs.id, prs.name
I would recommend aggregating each of the tables by the person and then joining the results back to the person table:
select p.*, coalesce(r.cnt, 0) + coalesce(l.cnt, 0) as numjobs
from person p left join
(select id, count(*) as cnt
from responsible
group by id
) r
on r.id = p.id left join
(select id, count(*) as cnt
from linked
group by id
) l
on l.id = p.id;
select id, name, count(process_no) FROM (
select pr.id, pr.name, res.process_no from Person pr
LEFT JOIN Responsible res on pr.id = res.id
UNION
select pr.id, pr.name, lin.process_no from Person pr
LEFT JOIN Linked lin on pr.id = lin.id) src
group by id, name
order by id
Query ain't tested, give it a shot, but this is the way you want to go

SQL QUERY USING POSTGRESQL

I have the following query:
SELECT DISTINCT "stylists".* FROM "stylists"
INNER JOIN "category_stylists" ON "category_stylists"."stylist_id" = "stylists"."id"
WHERE category_stylists.category_id IN (1,2)
But I want to order the stylists by categories.
For example:
Stylists
id | Name
1 Sebastian
2 Jhon
Categories
id | Name
1 Wedding
2 Office
Stylist_Categories
id | stylist_id | category_id
1 1 1
2 2 1
3 2 2
So If I apply my query, I got both Stylists, but I need always order by how many categories has the stylist. I mean in this example Jhon will be the first row because has the category_id 1 and category_id 2.
Result expected:
Stylists
id | Name
2 Jhon
1 Sebastian
Thanks in advance!
Try counting categories for each stylist and order by it:
SELECT "id","name" from(
SELECT "stylists"."id", "stylists"."Name",count(stylists.id) as cnt FROM "stylists"
INNER JOIN "category_stylists" ON "category_stylists"."stylist_id" = "stylists"."id"
WHERE category_stylists.category_id IN (1,2)
group by "stylists"."id", "stylists"."Name")
order by cnt desc

Return name of the employee who having top salary with join

here is the situation. I have two tables, one is table Tbl_employ, second is tbl_details.
Tbl_employ
----------
id | name
1 | Ravi
2 | ram
3 | sham
4 | john
Tbl_details
-----------
id | salary | emp_id
1 | 500 | 1
2 | 200 | 2
3 | 400 | 3
4 | 501 | 4
I want to return the name of the employee who has top salary in tbl_detail.
What will be the join query for this condition?
Please suggest. Thanks in advance.
Perhaps:
SELECT TOP(1) name
FROM Tbl_employ e INNER JOIN Tbl_details d ON e.id = d.emp_id
ORDER BY d.salary DESC;
Essentially, this joins the two tables on the key fields (id and emp_id), returning only a single result (TOP(1)) that is the maximum salary row (ORDER BY d.salary DESC).
I appreciate the answer of #Max Vernon.
You can also do it by another way. Please try this
select t.name from (
select Distinct top 1 salary ,name
from Tbl_employ as E
left outer join Tbl_details as D on D.empid=E.id
order by salary desc
) as t
you can check it here SQL Fiddle

SQL - Limiting to one row for matching results

Considering the tables below, how would I write a query that returns profession.profession when the profession.profession_id is present in contractor_has_profession.profession_id, but limiting it to one result for each profession.profession
So in this example the result would be [Coder, Database, Frontend]
contractor_has_profession
contractor_id | profession_id
1 | 5
2 | 5
3 | 5
4 | 2
5 | 1
profession
profession_id | profession
1 | Frontend
2 | Database
3 | Graphics
4 | Sound
5 | Coder
SELECT p.profession
FROM profession p
WHERE EXISTS(SELECT *
FROM contractor_has_profession c
WHERE c.profession_id = p.profession_id)
Hmm, this should be sufficient:
select distinct p.profession
from profession p
inner join contractor_has_profession c
where p.profession_id = c.profession_id
or if I'm wrong here, then try:
select p.profession
from profession p
inner join contractor_has_profession c
where p.profession_id = c.profession_id
group by p.profession