combine two tables in sql - sql-server-2008

By using Sql server 2008 I can return two table results like
College Department Course Section Passed
X CS B.Sc A 30
X CS B.Sc B 12
and the second result
College Department Course Section Failed
X CS B.Sc A 23
X CS B.Sc B 42
here, am joining one extra table than the first one, if I use the same query to get both the passed and failed count, the count goes wrong, thats what am using two different queries.
Am trying to combine these two tables, to get the result like
College Department Course Section Passed Failed
X CS B.Sc A 30 23
X CS B.Sc B 12 42
but I dunno how to do this, can anyone help me out here, thanks in advance.
Note : here am joining about 3 to 5 tables in both the queries.

select a.*b.failed
from ([first result query]) a
INNER JOIN ([second result query]) b on a.college=b.college and a.Department=b.Department and a.Course=b.course and a.Section=b.Section

Use case Statement
select College, Department , Course , Section ,
sum(case when <pass condition> then 1 else 0) as Passed ,
sum(case when <fail condition> then 1 else 0) as Failed
from <table1>
join <table2>
on (condition)
group by College, Department , Course , Section

You can use inner join for your required output.
For Example,
Select emp.name,emp.salary,Q.qualification from employee emp inner join qualification Q.empid=emp.empid
For detail refer
https://www.w3schools.com/sql/sql_join_inner.asp/
https://avtartime.com/sql-inner-join-with-examples/

Related

Eliminate certain duplicated rows after group by

With this db:
Chef(cid,cname,age),
Recipe(rid,rname),
Cooked(orderid,cid,rid,price)
Customers(cuid,orderid,time,daytime,age)
[cid means chef id, and so on]
Given orders from customers, I need to find for each chef, the difference between his age and the average of people who ordered his/her meals.
I wrote the following query:
select cid, Ch.age - AVG(Cu.age) as Diff
from Chef Ch NATURAL JOIN Cooked Co,Customers Cu
where Co.orderid = Cu.orderid
group by cid
This solves the problem, but if you assume that customers has their unique id, it might not work,because then one can order two meals of the same chef and affect the calculation.
Now I know it can be answered with NOT EXISTS but I'm looking for a soultion which includes the group by function (something similar to what I wrote). So far I couldn't find (I searched and tried many ways, from select distinct , to manipulation in the where clause ,to "having count(distinct..)" )
Edit: People asked for an exmaple. i'm coding using SQLFiddle and it crashes alot, so I'll try my best:
cid | cuid | orderid | Cu.age
-----------------------------
1 333 1 20
1 200 2 41
1 200 5 41
2 4 3 36
Let's say Chef 1's age is 50 . My query will give you 50 - (20+40+40/3) = 16 and 2/3. althought it should actually be 50 - (20+40/2) = 20. (because the guy with id 200 ordered two recipes of our beloved Chef 1.).
Assume Chef 2's age is 47. My query will result:
cid | Diff
----------
1 16.667
2 11
Another edit: I wasn't taught any particular sql-query form.So I really have no idea what are the differences between Oracle's to MySql's to Microsoft Server's, so I'm basically "freestyle" querying.(I hope it will be good in my exam as well :O )
First, you should write your query as:
select cid, Ch.age - AVG(Cu.age) as Diff
from Chef Ch join
Cooked Co
on ch.cid = co.cid join
Customers Cu
on Co.orderid = Cu.orderid
group by cid;
Two different reasons:
NATURAL JOIN is just a bug waiting to happen. List the columns that you want used for the join, lest an unexpected field or spelling difference affect the results.
Never use commas in the FROM clause. Always use explicit JOIN syntax.
Next, the answer to your question is more complicated. For each chef, we can get the average age of the customers by doing:
select cid, avg(age)
from (select distinct co.cid, cu.cuid, cu.age
from Cooked Co join
Customers Cu
on Co.orderid = Cu.orderid
) c
group by cid;
Then, for the difference, you need to bring that information in as well. One method is in the subquery:
select cid, ( age - avg(cuage) ) as diff
from (select distinct co.cid, cu.cuid, cu.age as cuage, c.age as cage
from Chef c join
Cooked Co
on ch.cid = co.cid join
Customers Cu
on Co.orderid = Cu.orderid
) c
group by cid, cage;

MySQL, How to select one row from first table and two from the second one

I need to SELECT one row from first table and two rows from second one that correspond to the result from the first one. I can explain it more clearly using example.
As shown below I have two tables. Table "Games" have information about games between teams (e.g. game nr 1 is played by team NR 10 and team NR 11). In second table I simply have teams' names. The question is how to using one Select get information about game together with teams names from second table?
e.g. I want to get information who plays game NR 3 together with teams' names. Result should be:
id = 3, team_nr1 = 14, team_nr2 = 15, team1_name = eee, team2_name = fff
Is it even possible?
Table: Games
________________________
id team_nr1 team_nr2
1 10 11
2 12 13
3 14 15
Table: Teams
________________________
team_id team_name
10 aaa
11 bbb
12 ccc
13 ddd
14 eee
15 fff
Thanks for any advice.
I think you want to use joins. It could look like this:
SELECT G.id, G.team_nr1, G.team_nr2,
T1.team_name AS team1_name, T2.team_name AS team2_name
FROM Games G
LEFT JOIN Teams T1 ON (G.team_nr1 = T1.team_id)
LEFT JOIN Teams T2 ON (G.team_nr2 = T2.team_id)
WHERE G.id = 3
There are also other types of joins. LEFT JOIN means that all games are listed, even if there are no matching teams in T1 or T2.
You could try:-
SELECT ID,
TEAM_NR1,
TEAN_NR2,
(SELECT TEAM_NAME
FROM TEAMS
WHERE TEAMS.TEAM_ID = GAMES.TEAM_NR1) AS TEAM1_NAME,
(SELECT TEAM_NAME
FROM TEAMS
WHERE TEAMS.TEAM_ID = GAMES.TEAM_NR2) AS TEAM2_NAME
FROM GAMES
WHERE GAMES.ID = 3;
The subqueries pick out the required team names and name the "column" in which they appear.
If you want to have only 1 row with all your values, the only way I can thing of is using the GROUP_CONCAT function. I would not recommend the use on inline queries oe subqueries because in case of no record found it will produce a mysql error.

Marking Records as duplicates in mySQL

I am not a databases guy,but I have been given the "fun" job of cleaning up someone else's database. We have many duplicate record in our databases and some of customers are getting double or triple billed every month.
Given the following Database example
:
Table: Customers
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 No
5 Tree Top 2127657654 No
Is it possible to write a query that Identifies the all duplicate phone numbers (in this case records 1 and 4) and then marks and duplicate records yes by updating the DoNotBill column. But leaves the first record unmarked.
In this example case we would be left with:
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 Yes
5 Tree Top 2127657654 No
something like this?
UPDATE
customers cust,
(SELECT
c1.ID,
c1.name,
c1.phone,
c1.DoNotBill
FROM customers c
LEFT JOIN
(SELECT
cc.ID
FROM customers cc
) as c1 on c1.phone = c.phone
) dup
SET cust.DoNotBill = 'Yes' WHERE cust.id=dup.id ;
To begin with I assume that the DoNotBill column only has two possible values; yes and no. In that case it should be bool instead of varchar, meaning it would be either true or false.
Furthermore I don't get the meaning of the DoNotBill column. Why wouldn't you just use something like this?
select distinct phone from customers
SQL SELECT DISTINCT
That would give you the phone numbers without duplicates and without the need for an extra column.
This depends on ur data amount
You can do it in steps and make use some tools like excel...
This qrt
SELECT a.id,b.id,a.phone FROM clients a , clients b WHERE
A.phone =b.phone
And a.id!=b.id
The result is all duplicated records.
Add
Group by a.phone
And u will get 1 record for each 2 duplicates.
if you like the records and they are whT u need. ChNge select to select a.id and
Use this qry as subqry to an update sql statement
UPDATE clients SET billing='no' WHERE id IN ( sql goes here)
UPDATE customers c SET c.DoNotBill="Yes";
UPDATE customers c
JOIN (
SELECT MIN( ID ) ID, Phone
FROM customers
GROUP BY Phone
) u ON c.ID = u.ID AND c.Phone = u.Phone
SET c.DoNotBill="No";
That way not only duplicates are eliminated, but all multiple entries are dealt with.

JOINS in the query end up displaying too many rows

Below is my query:
$query = "
SELECT DISTINCT gr.SessionId, t.TeacherUsername, t.TeacherForename,
t.TeacherSurname, cm.ModuleId, m.ModuleName,
cm.CourseId, c.CourseName, st.Year, st.StudentUsername,
st.StudentForename, st.StudentSurname, gr.Mark, gr.Grade
FROM Teacher t
INNER JOIN Session s ON t.TeacherId = s.TeacherId
JOIN Grade_Report gr ON s.SessionId = gr.SessionId
JOIN Student st ON gr.StudentId = st.StudentId
JOIN Course c ON st.CourseId = c.CourseId
JOIN Course_Module cm ON c.CourseId = cm.CourseId
JOIN Module m ON cm.ModuleId = m.ModuleId
WHERE
('".mysql_real_escape_string($sessionid)."' = '' OR gr.SessionId = '".mysql_real_escape_string($sessionid)."')
ORDER BY $orderfield ASC
";
You don't need to worry about the WHERE clause and ORDER BY clause. My problem is that the query result shows 26 rows when it should show 13 rows.
I know the reason for this and it is because the Course_Module table is a cross reference table between Course table and Module table and is needed so that it is able to link Course table and Module table together.
But Course Table uses CourseId to JOIN another table and so does Course_Module Table. So CourseId is used twice in the JOINS section and because of this it is duplicating rows again. So there should be 13 rows but because each row is duplicate it shows 26.
I tried GROUP BY cm.CourseId but it ends up displaying 2 rows which are two different CourseId which is not what I want at all.
So what my question is that is there are way I can use the Course_Module table to JOIN tables but ignore it when it comes to displaying results?
If query was this:
$query = "
SELECT DISTINCT gr.SessionId, t.TeacherUsername, t.TeacherForename,
t.TeacherSurname, cm.ModuleId, m.ModuleName,
cm.CourseId, c.CourseName, st.Year, st.StudentUsername,
st.StudentForename, st.StudentSurname, gr.Mark, gr.Grade
FROM Teacher t
INNER JOIN Session s ON t.TeacherId = s.TeacherId
JOIN Grade_Report gr ON s.SessionId = gr.SessionId
JOIN Student st ON gr.StudentId = st.StudentId
JOIN Course c ON st.CourseId = c.CourseId;
This query shows 13 rows but it means there is no link to Module Table so don't know name of Modules taken for each grade reort.
Below is example of result I am getting at moment:
Student Session Module Course Grade
S1 AAA CHT2520 ICT A
S1 AAA CHT2520 ICT A
S2 AAA CHT2520 ICT B
S2 AAA CHT2520 ICT B
S3 AAB CHT2220 BIT D
S3 AAB CHT2220 BIT D
S4 AAC CHI2250 COMP A
S4 AAC CHI2250 COMP A
It should be:
Below is result I am getting at moment:
Student Session Module Course Grade
S1 AAA CHT2520 ICT A
S2 AAA CHT2520 ICT B
S3 AAB CHT2220 BIT D
S4 AAC CHI2250 COMP A
Thank You
Your select clause asks for 14 columns. The results you showed only had 5. If you limit your select clause to those 5 columns, you'll get the 13 rows that you want.
To include all 14 columns, look at the other columns in the results. Realize that right now, you don't have 26 rows in your result set so much as you have 13 pairs of rows. Look carefully at each pair, and somewhere you'll find a column that's different — something that distinguishes one record in a matched pair from the other. Add a condition to the join on the table that hosts this column to prevent one of the values from making it to your results, and you'll get the right number of rows. This may require a derived table or correlated sub-query in the join condition to limit the join to only the first match (for some definition of "first" determined by the sub query).
I am not a big expert but why are you using two different joins in your case? Stick to INNER JOIN throughout the query and it might fix the issue.

Grouping, counting and excluding based on column value

Although I've not a complete newbie in SQL or MySQL I notice that there's still quite a bit to learn. I cannot get my head around this one, after much trying, reading and searching. If you can give any pointers, I'd be grateful.
I have simplified the actual data and tables to the following.
Two tables are relevant: Staff, and Work. They contain data on staff in various projects.
Staff:
ID Name Unit
1 Smith Chicago
2 Clarke London
3 Hess Chicago
Work:
StaffID ProjectID
1 10
2 10
3 10
1 20
2 30
3 40
1 50
3 50
Goal:
To get grouped all those projects where there are staff from Chicago, with the count of all staff in that project.
Expected result:
Project Staff count
10 3
20 1
40 1
50 2
So the project 30 is not listed because its member(s) are not from Chicago.
My query below is obviously wrong. It counts only those project members who are from Chicago, not the whole project staff.
SELECT
work.projectID as Project, COUNT(*) as "Staff count"
FROM
staff
JOIN
work ON staff.ID=work.staffID
WHERE
unit="Chicago"
GROUP BY
work.projectID;
I'd put the test for Chicago in a subselect.
Alternatively you can use a self-join, but I find the sub-select easier to understand.
SELECT
w.projectid as project
,COUNT(*) as `staff count`
FROM work w
INNER JOIN staff s ON (w.staffID = s.id)
WHERE w.projectID IN (
SELECT w2.projectID FROM work w2
INNER JOIN staff s2 ON (w2.staffID = s2.id AND s2.unit = 'Chicago'))
GROUP BY w.projectid
Remove the where clause and add a having clause which checks that at least one member of staff is from Chicago.
SELECT
work.projectID as Project, COUNT(*) as "Staff count"
FROM
staff
JOIN
work ON staff.ID=work.staffID
GROUP BY
work.projectID
HAVING
count(case unit when 'Chicago' then 1 end) > 0;
Finally: the result. Thanks again both #Johan and #a'r for your help, and #Johan for getting me on the right track (in my case).
I changed the sub-select to a derived table, and inner-joined this with the Work table on projectID.
SELECT
w.projectID AS project
,COUNT(*) AS `staff count`
FROM work w
INNER JOIN
(SELECT DISTINCT w2.projectID
FROM work w2
INNER JOIN staff s ON (w2.staffID = s.id AND s.unit = 'Chicago')) c
ON (w.projectID = c.projectID)
GROUP BY w.projectID