Join three table for Report in Mysql - php

I would like to produce report for airlines using
Date Table
Airline Table
Route Table
My date table include series of date
Entryid | Date
----------------
1 |2016-06-01
2 |2016-06-02
4 |2016-06-03
5 |2016-06-04
6 |2016-06-05
7 |2016-06-06
My airline table include
id|name
---------
1 |Air1
2 |Air2
3 |Air3
and Route table:
id|date |airline|routename
1|2016-06-01|1 |city1-city2
2|2016-06-01|1 |city1-city3
3|2016-06-01|2 |city1-city3
4|2016-06-02|2 |city1-city3
5|2016-06-02|2 |city1-city3
6|2016-06-04|2 |city1-city3
7|2016-06-04|2 |city1-city3
8|2016-06-04|1 |city1-city3
by using these three table I want to produce result as follow"
Date |Airline|totleroute
2016-06-01 | Air1 | 2
2016-06-01 | Air2 | 1
2016-06-02 | Air1 | 0
2016-06-02 | Air2 | 2
2016-06-03 | Air1 | 0
2016-06-03 | Air2 | 0
2016-06-04 | Air1 | 1
2016-06-04 | Air2 | 2
How to produce desired result from joining three tables?

You can use a query like the following:
SELECT d.`date`, t.`name`, COUNT(r.`routename`) AS TotalRoutes
FROM `Date` AS d
CROSS JOIN (
SELECT DISTINCT r.`airline`, a.`name`
FROM Route AS r
INNER JOIN Airline AS a ON r.airline = a.id
) AS t
LEFT JOIN Route AS r ON d.`date` = r.`date` AND t.`airline` = r.`airline`
GROUP BY d.`date`, t.`airline`
The CROSS JOIN is used in order to produce a result for each date - airline combination, as suggested by the sample output in the OP.
Demo here

Please try this query:
select e.date,a.name airline, count(r.id) total_route from route_tbl r
LEFT join entry_tbl e on r.date =e.date
LEFT join airline_tbl a on a.id= r.id
order by r.date
group by r.date

It seems you need a so called FULL JOIN to have all combinations of Date and Route entries with a column containing the number of routes per day and airline.
Regrettably MySQL lacks support for FULL JOIN, there is a feature request open since some years.
It is still possible to emulate such a feature. A good reading would be https://explainextended.com/2009/04/06/emulating-full-outer-join-in-mysql/

Related

mysql join query didnt get correct out put

I have 3 tables
admin_courses
Admin_course_groups
Group_permision
admin_courses
c_id | c_name | c_status
1 | test1 | 1
2 |test2 |1
3 |test3 |1
4 test4 1
Admin_course_groups
a_id | fk_c_id |fk_g_id |start_date |end_date
1 | 1 | 1 | 2018-10-10 |2018-10-20
2 | 5 |1 | 2018-10-10 | 2018-10-20
3 | 4 |3 |2018-10-10 |2018-10-20
Group_permision
gp_id|fk_g_id|user_id
1 1 2
2 3 2
2 1 3
Here total four courses added i want to know how many course assign to each user, i have query
SELECT c_id
, c_name
, COUNT(a_id) AS nam
, MIN(start_date) as start_date
, MIN(end_date) as end_date
FROM admin_courses c
LEFT
JOIN Admin_course_groups g
ON g.fk_c_id = c.c_id
left
join Group_permision h
on g. fk_g_id=h.fk_g_id
and users_id=3
where c.c_status=1
GROUP
BY c_id
So here it will return all course, if course is assigned for user COUNT(a_id) will 1 else it 0.
Now my issue is that if users_id is 3 user assigned only 1 course but i got 3 instead of 1.
Please help me. any help would be appreciated.
You are counting wrong field. To count number of Users in a Course, you need to count user_id; Also, use Count(Distinct ...) to avoid counting a same user multiple times.
Also, note that I have added c.c_name to Group By clause, to be compatible with only_full_group_by mode. Do Read: SELECT list is not in GROUP BY clause and contains nonaggregated column .... incompatible with sql_mode=only_full_group_by
You dont need to join on user_id, to count total number of users. It restricts your data.
Try:
SELECT c.c_id
, c.c_name
, COUNT(DISTINCT h.user_id) AS nam
, MIN(g.start_date) AS start_date
, MIN(g.end_date) AS end_date
FROM admin_courses AS c
LEFT
JOIN Admin_course_groups AS g
ON g.fk_c_id = c.c_id
LEFT
JOIN Group_permision AS h
on g.fk_g_id = h.fk_g_id
WHERE c.c_status=1
GROUP
BY c.c_id,
c.c_name
Your question is missing some crucial information, but if I understood the problem correctly, I would simply try to add Distinct to the count :
SELECT `c_id`, `c_name`, COUNT(distinct `a_id`)
....

Display Highest Offer, But Still Display With No Offer

I'm trying to display businesses along with their highest discount offer. But I still would like to display businesses with no offer.
Businesses are stored in business_tb
business_id | business_name
------------+---------------
1 | aaa
2 | bbb
3 | ccc
offered discounts by those businesses are stored in deal_offer_tb
deal_offer_id | business_id | deal_id
--------------+-------------+----------
1 | 1 | 3
2 | 1 | 2
3 | 2 | 0
4 | 1 | 1
5 | 3 | 3
and types of discounts are stored in deal_tb.
deal_id | discount
--------+----------
1 | 40%
2 | 30%
3 | 20%
4 | 10%
So the display I wanted should look something like this:
1 | aaa | 40%
2 | bbb | ---
3 | ccc | 20%
But with my current query:
SELECT a.business_id, a.business_name, c.discount
FROM business_tb a
LEFT JOIN (SELECT min(deal_id) AS deal_id, business_id FROM deal_offer_tb GROUP BY business_id) b ON a.business_id = b.business_id
LEFT JOIN deal_tb c ON b.deal_id = c.deal_id
I only get:
1 | aaa | 40%
3 | ccc | 20%
It does not display businesses with no offered discounts.
How am I suppose to get my desired output?
UPDATE: I don't know what happened earlier, but my query is working the way I wanted it. Thanks to the effort of those who answered. Appreciate it, big time!
I would approach this by using a subquery to find the greatest discount for each business, joining the deal_offer_tb and deal_tb tables. Then, join this subquery to the business_tb table to get the final result. Note that I use an initial LEFT JOIN to account for that a given business may not even have an deals associated with it. In that case, I assign a maximum discount of 0 to that business (which makes sense, since then the full regular price would apply).
SELECT
t1.business_id,
t1.business_name,
COALESECE(t2.max_discount, 0) AS max_discount
FROM business_tb t1
LEFT JOIN
(
SELECT t1.business_id, MAX(t2.discount) AS max_discount
FROM deal_offer_tb t1
INNER JOIN deal_tb t2
ON t1.deal_id = t2.deal_id
GROUP BY t1.business_id
) t2
ON t1.business_id = t2.business_id
This query is essentially your query (with table aliases):
SELECT b.business_id, b.business_name, d.discount
FROM business_tb b LEFT JOIN
(SELECT MIN(deal_id) AS deal_id, business_id
FROM deal_offer_tb dot
GROUP BY business_id
) dot
ON b.business_id = dot.business_id LEFT JOIN
deal_tb d
ON d.deal_id = dot.deal_id;
By the definition of LEFT JOIN, it will keep all rows in business_tb, regardless of whether or not there are matches in the rest of the FROM clause. You have no additional filtering (via WHERE) or aggregation. Hence, this should returns all the rows in business_tb.
Below is one way to do the query:
SELECT
a.business_id, a.business_name, b.max
FROM business_tb a
INNER JOIN (
SELECT
c.business_id, MAX(d.discount) AS max
FROM deal_offer_tb c
LEFT JOIN deal_tb d ON c.deal_id = d.deal_id
GROUP BY c.business_id
) b ON a.business_id = b.business_id;
You don't have deal_id 0 in deal_tb, so I assume it's null for deal_offer_id 3.

How to join two tables without duplicates?

I have an in table that looks like this:
id_in | date_in
-------|--------------------------
1 | 2016-04-29 02:00:00
And an out table that looks like this:
id_out | date_out
----------|--------------------------
1 | 2016-04-29 03:00:00
2 | 2016-04-29 04:00:00
3 | 2016-04-29 05:00:00
I want to write a query whose output looks like this:
id_in | date_in | id_out | date_out
------|---------------------------- |----------------------------|---------------------------
1 | 2016-04-29 02:00:00 | 1 |2016-04-29 03:00:00
NULL | NULL | 2 |2016-04-29 04:00:00
NULL | NULL | 3 |2016-04-29 05:00:00
You can do this with a left join:
select i.id_in, i.date_in, o.id_out, o.date_out
from outtable o left join
intable i
on o.id_in = i.id_out;
Or you can do this with a right join
select i.id_in, i.date_in, o.id_out, o.date_out
from intable i right join
outtable o
on o.id_in = i.id_out;
Let's call the table with id_in 'table_in' and the table with id_out 'table_out'
You want to join table_in to table_out. In this case, you want to left join table_in to table_out on the id field. This will ensure you return all records from table_out regardless of whether they have a corresponding record in table_in:
select table_in.id_in, table_in.date_in, table_out.id_out, table_out.date_out
from table_out
left join table_in
on table_out.id_out = table_in.id_in
(Alternatively, you can table_in right join table out for the same results)
If you want all the records from both tables regardless of whether there is a corresponding record in the other, you should use full join.
simple you can try this
select * from table_id i right join table_out o on i.id_in = o.id_out
This query results the same as your need..
SELECT a.id_in, a.date_in, b.id_out, b.date_out
FROM intable AS a RIGHT JOIN
outtable AS b
ON a.id_in = b.id_out

Obtaining last occurance of row on MySQL LEFT JOIN

I have the following tables in my Database:
USERS
+-------+-------------------------------------+
| id | name |
+-------+-------------------------------------+
| 1 | Johnny Appleseed |
| 2 | Pete Jones |
| 3 | John Doe |
| 4 | Jane Plick |
+-------+-------------------------------------+
REPORTS
+-------+-------+-----------------------------+
| id | owner | title |
+-------+-------+-----------------------------+
| 1 | 1 | Weekly report #86 |
| 2 | 1 | Weekly report #87 |
| 3 | 1 | Weekly report #88 |
| 4 | 2 | Weekly report #1 |
| 5 | 3 | Weekly report #33 |
| 6 | 3 | Weekly report #34 |
+-------+-------------------------------------+
What I need to do is GROUP the results by first name, so that the list itself is alphabetical order, but I need the LAST occurrence of the row matching the user's id.
The "owner" column of the REPORTS table matches the "id" column of the USERS table.
My desired results look like:
Jane Plick |
John Doe | Weekly Report #34
Johnny Appleseed | Weekly Report #88
Pete Jones | Weekly Report #1
My current query ALMOST works, however it only shows the FIRST weekly report for that user, not the last.
SELECT * FROM users AS a LEFT JOIN ppp_reports AS b ON a.id=b.owner WHERE a.active=1 GROUP BY a.id ORDER BY a.firstname ASC
I have tried a lot of different variations, but I'm always left with the FIRST row from the REPORTS table.
Any help is greatly appreciated.
In your particular case where all reports are named "Weekly report #X", you can try this:
SELECT a.id, a.name, MAX(b.title)
FROM users AS a
LEFT JOIN ppp_reports AS b ON a.id=b.owner
WHERE a.active=1
GROUP BY a.id, a.name
ORDER BY a.name ASC
See this fiddle.
If the reports may have other names, you'll have to find another way to discriminate the last report from the others.
Assuming that your reports ID are numbered by date, i.e report ID 2 is always after report ID 1, these two queries should work:
select t.id, t.name, r.title from
(select u.id, u.name, max(r.id) as report_id
from users u
left join reports r on r.owner = u.id
group by u.id, u.name) as t
left join reports r on t.report_id = r.id;
OR
select u.id, u.name, r.title from
users u
left join
(select r.owner, max(r.id) as report_id
from reports r
group by r.owner) as latest_report on u.id = latest_report.owner
left join reports r on latest_report.report_id = r.id;
The idea is that you need to identify the correct report, by user ID, and then join the reports table back to that to get the correct name for the report.
Link to SQL Fiddle

SQL inner join of multiple tables and search through database

I'm making a search function in PHP and I have three tables that I wish to join to a single one; the three tables looks as follow:
band
ID | bands
---+----------
1 | Muse
2 | Coldplay
3 | etc.
release
ID | releases
---+----------
1 | Showbiz
2 | Origin of Symmentry
3 | etc.
track
ID | tracks
---+-----------
1 | Sunburn
2 | Muscle Museum
3 | etc.
I want these tables to be put into this:
discografic
ID | band_id | release_id | track_id
---+----------+-------------+---------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | etc.
So that the table with the SQL code looks like this:
discografic
ID | bands | releases | tracks
---+----------+-------------+---------
1 | Muse | Showbiz | Sunburn
2 | Muse | Showbiz | Muscle Museum
3 | etc.
I want to INNER JOIN these tables. I joined one but I can't really figure out how the get the last joined as well.
SELECT *
FROM band
INNER JOIN discografic
ON band.id = discografic.band_id
This should probably have its own question; I also want to be able to search this database, but only have the result show up once, and also reference to the band every time. For example, if I search "Showbiz" it will give me "Muse", and only show it once.
Note: This is for testing purposes only, security is none of my concerns.
Try with this query:
select d.id,b.bands,r.releases,t.tracks from discografic as d INNER JOIN band as b on
d.band_id=b.id INNER JOIN release as r on d.release_id=r.id INNER JOIN track as t on
d.track_id=t.id GROUP BY d.id
Try This query
Select a.ID,b.bands,c.releases,d.tracks from discografic as a
inner join band as b on a.band_id = b.ID
inner join release as c on a.release_id = c.ID
inner join track as d on a.track_id = d.ID
where b.bands = 'Muse'
Use this query to insert the data like you wanted:
Insert into discograpy
(id,bands,releases,tracks)
SELECT band.ID,bands,releases,tracks
FROM band
INNER JOIN releases
ON band.id = releases.id
inner join track
on band.id = track.id
Use this query to show you only one band:
Declare #releases varchar(50)
Set #releases = 'showbiz'
SElect distinct bands from discograpy where releases = #releases
Here any variable can be passed or set in place of showbiz. This is an example

Categories