Difference between Equi-Join and Inner-Join in SQL - sql-server-2008

I have 2 tables called 'table123' and 'table246'.
'table123' columns: 'ID', 'Dept_ID', 'First_Name', 'Surname', 'Salary', 'Address'.
'table246' columns: 'Dept_ID', 'Dept_Name'.
I want to find the list of employees with the lowest salary per department. Two of the ways I can do it is an Equi-Join or an Inner-Join. I've been told they can both be used to provide the desired result.
The queries I used:
Equi-Join:
SELECT First_Name, b.Dept_Name, alt.Min_Salary AS Min_Salary
FROM table123 a, table246 b,
(SELECT Dept_ID, MIN(Salary)Min_Salary
FROM table123
GROUP BY Dept_ID)alt
WHERE a.Dept_ID = b.Dept_ID
AND a.salary = alt.Min_Salary
AND a.Dept_ID = alt.Dept_ID;
Inner-Join:
SELECT MIN(Salary)Min_Salary, Dept_Name
FROM table123 a, table246 b
INNER JOIN (SELECT First_Name, MIN(Salary)
FROM table123
GROUP BY Dept_ID)alt
ON b.Dept_ID = alt.Dept_ID;
The Equi-Join statement gives me the desired table, containing the columns 'First_Name', 'Dept_Name' & 'Min_Salary', with all relevant data.
However, the Inner-Join statement doesn't run because the First_Name column needs to be included in the aggregate function or GROUP BY clause. This really confuses me, as I don't know how to go about fixing it. How can I adjust the Inner-Join query, so as to give the same result as the Equi-Join query?

Try this:
SELECT a.First_Name, b.Dept_Name, alt.Min_Salary AS Min_Salary
FROM table123 a
INNER JOIN table246 b
ON a.Dept_ID = b.Dept_ID
INNER JOIN (
SELECT Dept_ID, MIN(Salary) Min_Salary
FROM table123
GROUP BY Dept_ID
) alt
ON b.Dept_ID = alt.Dept_ID
WHERE a.Salary = alt.Min_Salary;

Related

Simple SQL query returning null value

I just started studying SQL queries.
I am practicing on this site: https://www.techonthenet.com/sql/joins_try_sql.php
I want to find:
"the name of the employee with the highest salary for every department".
My query is:
SELECT first_name, max(salary) FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY employees.dept_id
And I get null value for first_name :
I understand that the problem is due to the group by expressions. But how can I solve this?
Tables:
You can alternatively use row_number() like below, you don't need to join to departments table unless you need to show the name of the department:
Select e.*
from employees e
INNER JOIN
(
SELECT e.id, e.dept_id. e.first_name,
rn=row_number() over (partition by e.dept_id order by e.salary desc)
FROM employees e
) x ON x.id = e.id
where x.rn = 1
EDIT
(Since OP does not want to use row_number() function amd it turned out the query will be used in mysql instead of sql server) -> Can you please try this:
select em.*
from employees em, (
Select dept_id, max(salary) salary
from employees e
group by dept_id
) x on x.dept_id=em.dept_id and x.salary = em.salary
That should work but the online compiler does not accept join with a sub-query as far as I understand. Easiest solution I can think of, in this case:
select em.*
from employees em
where salary = (select max(salary) from employees em2 where em.dept_id = em2.dept_id)
SELECT top 2 first_name,max(salary) FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY first_name
order by max(salary) desc
try this:
SELECT e.first_name, e.salary FROM employees as e
INNER JOIN departments as d ON d.dept_id=e.dept_id
WHERE e.salary IN (SELECT max(salary) FROM employees GROUP BY dept_id)
Try this:
select first_name, b.dept_id, salary from employees a,
(
SELECT employees.dept_id, max(salary) as salary FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY employees.dept_id
)b where a.salary = b.salary and a.dept_id= b.dept_id

Making sense of Inner-Join with Sub-query in SQL Server 2008

I have 2 tables called 'table123' and 'table246'.
'table123' columns: 'ID', 'Dept_ID', 'First_Name', 'Surname', 'Salary', 'Address'.
'table246' columns: 'Dept_ID', 'Dept_Name'.
I want to find the Average Salary for each 'Dept_Name'. So I tried using the query below, which is an Equi-Join with a Sub-query:
SELECT Dept_Name, alt.Average_Salary AS Avg_Salary
FROM table123 a, table246 b,
(SELECT Dept_ID, AVG(Salary)Avg_Salary
FROM table123
GROUP BY Dept_ID)alt
WHERE a.Dept_ID = alt.Dept_ID
AND a.Salary = alt.Average_Salary
AND a.Dept_ID = b.Dept_ID;
However, when I run the above query, it gives the desired 2 column names 'Dept_Name' and 'Avg_Salary', but with no data in it (just a blank table).
What am I doing wrong in the code, which is causing this blank result table?
Also, is there an alternative method of getting the same result, using an Inner- Join? The Equi-Join is quite confusing.
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Your query does not return results because no one has exactly the average value, so the salary condition fails. Based on what you are selecting, the subquery is the query you want:
SELECT Dept_ID, AVG(Salary) as Avg_Salary
FROM table123
GROUP BY Dept_ID;
Presumably, the other table brings in the name, so:
SELECT b.Dept_Name, AVG(a.Salary) as Avg_Salary
FROM table123 a JOIN
table246 b
ON a.Dept_ID = b.Dept_Id
GROUP BY b.Dept_Name;
What about:
SELECT Dept_Name, alt.Avg_Salary
FROM table246 b
INNER JOIN (SELECT Dept_ID, AVG(Salary)Avg_Salary
FROM table123
GROUP BY Dept_ID)alt ON B.DEPT_ID = ALT.DEPT_ID
Go through this maybe it will help you.
http://www.databasejournal.com/features/mysql/article.php/3835506/Fetching-Data-from-Multiple-Tables-using-Joins.htm

Two table joins for one query -- confusing result

I'm trying to execute two separate inner table joins in my query to return values from two tables.
SELECT pname, avg(salary)
FROM project p INNER JOIN department d on p.dnum = d.dnumber
INNER JOIN employee e ON e.dno = d.dnumber;
I'm getting one row in the result set... pname = null, avg(salary) = null.
Result set should contain 11 rows because there are 11 projects in the schema.
Can someone point me in the right direction?
Thank you
You are missing the group by:
SELECT pname, avg(salary)
FROM project p INNER JOIN
department d
on p.dnum = d.dnumber INNER JOIN
employee e
ON e.dno = d.dnumber
GROUP BY pname;
In most databases, your version would fail with an obvious syntax error. MySQL only enforces the ANSI standard if you use the ONLY_FULL_GROUP_BY mode (see here).
Use left outer join instead of inner join
Or can you show me your data tables
Do you need the department table in your query?
Does the following query return all the data you need to summarize?
SELECT pname, salary
FROM ( SELECT salary, dno AS dnum FROM employee ) e
NATURAL JOIN project;
If it does, then this might be the summarization you require:
SELECT pname, AVG( salary ) AS average_salary
FROM ( SELECT salary, dno AS dnum FROM employee ) e
NATURAL JOIN project
GROUP
BY pname;

Select from one table with count from two other tables

I'm doing a query where i select all from a table called employee and want to do a count of employee_id from two other tables and represent the count in 2 seperate columns.
The tables:
employee [id, etc.]
report [id, employee_id, etc.]
office_report[id, employee_id, etc.]
What i did so far is:
SELECT emp.*, COUNT(rep.id ) no_of_field_reports, COUNT(of_rep.id) no_of_office_reports
FROM employee emp
LEFT JOIN report rep
ON (emp.id = rep.employee_id)
LEFT JOIN office_report of_rep
ON (emp.id = of_rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
The problem is, as soon as i have reports in BOTH report tables the count messes up. Say i have 16 reports in report table and 2 in office_report table, the count for no_of_field_reports and no_of_office_reports will become 32.
Im missing something obviously but as I'm not a SQL genius I can't figure out what.
Please make sure to explain what is causing the problem so I'm able to learn from my mistakes and get a better understanding of these type of queries as this is not going to be the last time.
I guess the answer will be the same for mariaDB, mySQL, and SQL in general so i added all those tag's for the sake of attention..
Possibly one approach if you're after distinct counts ( though you may need to adjust to the PK field)
SELECT emp.*,
COUNT(distinct rep.id ) no_of_field_reports, --may need to be on Unique key instead
COUNT(distinct of_rep.id) no_of_office_reports --may need to be on Unique key instead)
FROM employee emp
LEFT JOIN report rep
ON (emp.id = rep.employee_id)
LEFT JOIN office_report of_rep
ON (emp.id = of_rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
An approach getting the counts before the joins if you're not after a distinct count then this is likely the right approach and offers flexibility.
SELECT emp.*, rep.cnt, of_Rep.cnt
FROM employee emp
LEFT JOIN (SELECT count(ID) cnt , employee_ID
FROM REPORT
GROUP BY employee_ID) rep
ON (emp.id = rep.employee_id)
LEFT JOIN (SELECT count(ID) cnt, Employee_ID
FROM office_report
GROUP BY employee_ID) of_rep
ON (emp.id = of_Rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
or use of correlated queries (but not supported all the time Such as when creating materialized views from this SQL)
SELECT emp.*,
(SELECT count(ID)
FROM REPORT
WHERE emp.id = rep.employee_id) Report_Cnt,
(SELECT count(ID)
FROM office_report of_REP
WHERE emp.id = of_Rep.employee_id) of_Rep_Cnt
FROM employee emp
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC

multiple count from multiple tables and also group by grade

i have table with student_uid,grade,test_name as columns i want to count how many got each grade..for this
SELECT a.grade,COUNT(a.grade) AS count1
FROM 2015_2016_x_english_grades AS a
where test_name='ut1_marks'
GROUP BY grade
for single table worked how to do it for more than one table
my query:
SELECT a.grade, COUNT(a.grade),b.grade,COUNT(b.grade)
FROM 2015_2016_x_english_grades a
INNER JOIN 2015_2016_x_hindi_grades b ON a.grade=b.grade
WHERE a.test_name = b.ut1_marks='ut1_marks'
GROUP BY a.grade,b.grade
what is wrong in this?
i also tried this
SELECT a.grade,COUNT(a.grade),(SELECT COUNT(b.grade)FROM 2015_2016_x_biology_grades b where b.test_name='ut1_marks' GROUP BY b.grade)as count1 FROM 2015_2016_x_biology_grades a where test_name='ut1_marks' GROUP BY a.grade
it says [Err] 1242 - Subquery returns more than 1 row
Do the counting in subqueries, and join the subqueries.
SELECT e.grade, english_count, hindi_count
FROM (SELECT grade, COUNT(*) AS english_count
FROM 2015_2016_x_english_grades
WHERE test_name = 'ut1_marks'
GROUP BY grade) AS e
JOIN (SELECT grade, COUNT(*) as hindi_count
FROM 2015_2016_x_hindi_grades
WHERE test_name = 'ut1_marks'
GROUP BY grade) AS h
ON e.grade = h.grade
Or if there's a unique key in each table, you can do:
SELECT e.grade, COUNT(DISTINCT e.id) AS english_count, COUNT(DISTINCT h.id) AS hindi_count
FROM 2015_2016_x_english_grades AS e
JOIN 2015_2016_x_hindi_grades AS h ON e.grade = h.grade AND e.test_name = h.test_name
WHERE e.test_name = 'ut1_marks'
GROUP BY e.grade
Note that both of these queries will only show a grade if it exists in both tables. To get grades that only exist in one table, you need a FULL OUTER JOIN, but MySQL doesn't have this operation. See
Full Outer Join in MySQL
for how to emulate them.