How to join multiple queries with different tables and different column name - mysql

I want to join multiple queries with different tables and column name, along with I need to display the count of duplicate fields as shown below.
The queries are: (Proj_uid is common in all the tables which I need to match)
select proj_name,Agency,District,Division,Proj_status from tempproj
Need to join 2 tables to get the result that is payment80 and payment20 which contains billtype column with duplicate values, I want to count those value too
SELECT p.Proj_name,p.billtype, COUNT(1) as CNT
FROM payment80 p where billtype='civil'
GROUP BY Proj_name, billtype
(This is by using single table but I want this result by joining both payment80 and payment20 tables)
SELECT p.Proj_name,p.billtype, COUNT(1) as CNT
FROM payment80 p where billtype='Electric'
GROUP BY Proj_name, billtype
(The billtype values I want to count and just display a number of duplicate records)
Proj_Name billtype
------------------------
policegruha civil
gruhayojna Electric
policegruha civil
dcoffice civil
spoffice Electric
dcoffice civil
3) Select billtype from payment, here also I need count the duplicate values and display in billtype
Duplicate values will be in billtype which contains some thing like this:
Finally I want an output like this:
Proj_name Agency District Division Projstatus Civilbilltype Electricbilltype
policegruha kumar chitradurga davangere ongoing 3 1
gruhayojna khan ballary ballary completed 2 2
Atered john bangalore bangalore ongoing 2 4
dcoffice ravi mangalore mangalore ongoing 1 2
spoffice mary chitradurga davangere completed 3 4
hostel jack ballary ballary completed 3 3
univercity kumar bangalore bangalore ongoing 4 2
mess Raj mysore mysore ongoing 2 1
policestation khan mysore mysore ongoing 1 4
conferencehall Rosy davangere davangere ongoing 2 2

You are joining three separate tables. One is physical, tempproj, and the other two are virtual: they are aggregates.
This is the technique.
SELECT p.proj_name,p.Agency,p.District,p.Division,p.Proj_status,
Civilbills.billcount as Civilbills,
Electribills.billcount as Electricbills
FROM tempproj p
LEFT JOIN (
SELECT Proj_name, COUNT(*) as billcount
FROM payment80
where billtype='civil'
GROUP BY Proj_name
) Civilbills ON Civilbills.Proj_name = p.proj_name
LEFT JOIN (
SELECT Proj_name, COUNT(*) as billcount
FROM payment80
where billtype='Electric'
GROUP BY Proj_name
) Electricbills ON Electricbills.Proj_name = p.proj_name
Your requirement includes two separate aggregates from the payment80 table. The LEFT JOINs prevent suppression of project rows that lack any bills of either category.

Related

Query that provides the names of the recruiters that hire more than 3 employees, and the number of employees that were not hired by a recruiter

I'm a bit stuck on this question and was hoping for some help. Here's where I'm at currently.
I have this TEST table of Names. Each Person can either be a recruiter or an employee. The number in Recruited_by is associated with the person_id.
Person_id Name Recruited_by
1 Jean Grayson 1
2 Paul Smith 7
3 John Do Null
4 Alex Lee 7
5 Lisa Kim 7
6 Bob Thompson 3
7 Mike Keen Null
8 Raymond Red 3
9 Alisson Jones 1
10 Kate James 3
Here is the query I have so far which I'm trying to the names of the recruiters that hire more than 3 employees (which will return nothing in this case) and the number of employees that were NOT recruited by anyone (which would be the NULL names).
SELECT T.Name as Employees, COUNT(T1.Name) as Not_hired
FROM Test AS T
WHERE COUNT(T1.Name) IS NULL
LEFT OUTER JOIN Test AS T1
ON T.Recruited_by = T1.Person_id
GROUP BY T.Name
HAVING COUNT(T1.Name) > 3
However this query is returning nothing when I should expect it to return the number of employees who were not hired by a recruiter!
If you want in the results only 1 row with 2 columns then you can do a LEFT join of the table to a query that aggregates to get the ids of the persons that hired more than 3 persons and aggregate again to get the number of persons that were not recruited by anyone:
SELECT GROUP_CONCAT(CASE WHEN t2.Recruited_by IS NOT NULL THEN t1.Name END ORDER BY t1.Name) names,
SUM(t1.Recruited_by IS NULL) total_not_recruited
FROM Test t1
LEFT JOIN (
SELECT Recruited_by
FROM Test
GROUP BY Recruited_by
HAVING COUNT(*) > 3
) t2 ON t2.Recruited_by = t1.Person_id;
You will get the names of the persons that hired more than 3 persons (if they exist) as a comma separated list.
See the demo.

Select from two tables mysql in a particular order because the output must have a particular structure

I have a unique situation where I have to select particular columns from two tables in a particular order. Below is the table for the vendors
vid
company
mno
phone
1
Xoxoxo
MTN
2459999999
2
Vovovo
MTN
2459998888
3
Yrewmi
Vodafone
2459997777
Here is the order_content table.
oid
vendor_id
amount
2
2
2
2
1
4
2
1
7
3
1
1
I want to select the vendor.company, vendor.mno, SUM(order_content.amount), vendor.phone for a particular ordercontent.oid selecting only vendors involved. I want to get the vendors details from the vendor table and sum up the amount for a particular order. Lets say order 2 that is old = 2.
SELECT DISTINCT vendor.company AS customerName, vendor.mno, SUM(orders_content.price) AS amount
FROM orders_content, vendor
WHERE orders_content.oid = 2
GROUP BY orders_content.oid;
The result I am expecting
customerName
mno
amount
phone
description
reference
Vooxoo
MTN
2
2459998888
orders
154013949
Xoxoxo
MTN
11
2459999999
orders
78793949
You need to specify a joining condition between the tables, and group by vid, not oid. You don't need to group by oid since the WHERE clause restricts to a single order.
SELECT vendor.company AS customerName, vendor.mno, SUM(orders_content.price) AS amount
FROM vendor
JOIN orders_content ON orders_content.vendor_id = vendor.vid
WHERE orders_content.oid = 2
GROUP BY vendor.vid

SQL join with self

I have a table with ID numbers of people and then items of food they've ordered:
table "food_id"
food id
ham 1
cheese 2
turkey 2
ham 3
ham 4
bread 5
cheese 6
turkey 6
cheese 7
And I'd like to use SQL to figure out, for each id, the total number of other IDs who ordered at least one of the same food items. For the above example, the answer should be:
"result_table"
count id
3 1
3 2
3 3
3 4
1 5
3 6
3 7
The challenge is to avoid double counting here. For example, person number 2 got both cheese and turkey, so we want his final count to be 3 because person # 2, 6, and 7 got cheese, and person # 2 and 6 got turkey, and there are 3 unique IDs in this list of (2,6,7,2,6).
My initial thoughts were to first get a table with food items to distinct ID numbers, and then to join this table with the original table and then group by ID number and get a count of the distinct number of IDs. However, I'm a beginner to SQL and can't figure out how to implement the code correctly.
Any direction would be greatly appreciated.
To avoid the problem with the double counting you can concat both ids from the join and count only distinct combinations. I add a separator to make the combination unique with greater id values:
SELECT
COUNT(DISTINCT CONCAT(f1.id, ',', f2.id)) as count,
f1.id
FROM
food_id f1
INNER JOIN
food_id f2
ON
f1.food = f2.food
GROUP BY f1.id;
See demo
Like you said, you can do a self join. You can join by food, and count the number of distinct matching ids.
select
a.id, -- Person you're investigating
count(distinct b.id) as samefoodcount -- number of people sharing the same food
from
food_id a
inner join food_id b on b.food = a.food
group by
a.id
Here you can see the query in action: http://sqlfiddle.com/#!2/c53884/1
You can run the following query to get the desired output:
select MAX(T.total),id
from table_name, (select count(*) as total,food from table_name group by food) T
where table_name.food=T.food
group by id
Check the DEMO

MySQL GROUP_CONCAT and Multiple Lookup Tables

I Have seven tables I am trying to join:
Table programs
Column id program_name program_description
1 Self Help Self Help Description...
2 Wellness Wellness Description...
3 Education Education Description...
______________________________________________________
Table county
Column id county_name
1 Stark
2 Portage
3 Wayne
_________________________
Table services
Column id service_name service_description
1 Counseling Counseling Description...
2 Group Therapy Group Therapy Description...
3 Evaluation Evaluation Description...
__________________________________________________________
Table population
Column id population_name
1 Adults
2 Children
3 Youth
_____________________________
Table program_county
Column id program_id county_id
1 1 2
2 1 3
3 2 1
4 2 2
_____________________________________
Table program_service
Column id program_id service_id
1 1 2
2 1 3
3 2 1
4 2 2
5 2 3
______________________________________
Table program_population
Column id program_id population_id
1 1 3
2 2 1
3 2 3
4 3 1
_________________________________________
I am trying to write a query that would return one row for each program and retrieve the related rows in program_county,program_services, and program_population tables and lookup the names of those services, population and counties display them in one field each. Like:
id program_name program_description Counties Services Population Served
1 Self Help Self Help Description... Portage, Wayne Group Therapy, Evaluation Youth
2 Wellness Wellness Description Stark, Portage Counseling, Group Therapy, Evaluation Adults, Youth
I know I have to use joins and GROUP_CONCAT but I am admittedly very lost.
You'll want to use outer joins if you want to see all programs regardless of whether they are associated to counties, services, or populations. Likewise you should use coalesce() around the values you are concatenating to handle NULL values properly.
Something like this should work:
select programs.id, programs.program_name, programs.program_description,
group_concat(distinct coalesce(county.county_name,'')) as "Counties",
group_concat(distinct coalesce(services.service_name,'')) as "Services",
group_concat(distinct coalesce(population.population_name,'')) as "Population Served"
from programs
left outer join program_county on program_county.program_id = programs.id
left outer join county on county.id = program_county.county_id
left outer join program_service on program_service.program_id = programs.id
left outer join services on services.id = program_service.service_id
left outer join program_population on program_population.program_id = programs.id
left outer join population on population.id = program_population.population_id
group by programs.id, programs.program_name, programs.program_description
order by programs.id

Grouping and Accumulating Records at the same time

I am writing a query against an advanced many-to-many table in my database. I call it an advanced table because it is a many-to-many table with and extra field. The table maps data between the fields table and the students table. The fields table holds potential fields that a student can used, kind of like a contact system (i.e. name, school, address, etc). The studentvalues table that I need to query against holds the field id, student id, and the field answer (i.e. studentid=1; fieldid=2; response=Dave Long).
So my table looks like this:
What I need to do is take a few passed in values and create a grouped accumulated report. I would like to do as much in the SQL as possible.
So that data that I have will be the group by field (a field id), the cumulative field (a field id) and I need to group the students by the group by field and then in each group count the amount of students in the cumulative fields.
So for example I have this data
ID STUDENTID FIELDID RESPONSE
1 1 2 *(city)* Wallingford
2 1 3 *(state)* CT
3 2 2 *(city)* Wallingford
4 2 3 *(state)* CT
5 3 2 *(city)* Berlin
6 3 3 *(state)* CT
7 4 2 *(city)* Costa Mesa
8 4 3 *(state)* CA
I am hoping to write one query that I can generate a report that looks like this:
CA - 1 Student
Costa Mesa 1
CT - 3 Students
Berlin 1
Wallingford 2
Is this possible to do with a single SQL statement or do I have to get all the groups and then loop over them?
EDIT Here is the code that I have gotten so far, but it doesn't give the proper stateSubtotal (the stateSubtotal is the same as the citySubtotal)
SELECT state, count(state) AS stateSubtotal, city, count(city) AS citySubtotal
FROM(
SELECT s1.response AS city, s2.response AS state
FROM studentvalues s1
INNER JOIN studentvalues s2
ON s1.studentid = s2.studentid
WHERE s1.fieldid = 5
AND s2.fieldid = 6
) t
GROUP BY city, state
So to make a table that looks like that, I would assume something like
State StateSubtotal City CitySubtotal
CA 1 Costa Mesa 1
CT 3 Berlin 1
CT 3 Wallingford 2
Would be what you want. We can't just group on Response, since if you had a student answer LA for city, and another student that responds LA for state (Louisiana) they would add. Also, if the same city is in different states, we need to first lay out the association between a city and a state by joining on the student id.
edit - indeed, flawed first approach. The different aggregates need different groupings, so really, one select per aggregation is required. This gives the right result but it's ugly and I bet it could be improved on. If you were on SQL Server I would think a CTE would help but that's not an option.
select t2.stateAbb, stateSubtotal, t2.city, t2.citySubtotal from
(
select city, count(city) as citySubTotal, stateAbb from (
select s1.Response as city, s2.Response as StateAbb
from aaa s1 inner join aaa s2 on s1.studentId = s2.studentId
where s1.fieldId = 2 and s2.fieldId=3
) t1
group by city, stateabb
) t2 inner join (
select stateAbb, count(stateabb) as stateSubTotal from (
select s1.Response as city, s2.Response as StateAbb
from aaa s1 inner join aaa s2 on s1.studentId = s2.studentId
where s1.fieldId = 2 and s2.fieldId=3
) t3
group by stateabb
) t4 on t2.stateabb = t4.stateabb