MySql Join two tables with multiple columns - mysql

I have two tables
tblcities:
id | name
----------------
1 | Bahawalpur
2 | Multan
3 | Karachi
4 | Lahore
tblflights:
id | from_city_id | to_city_id
-------------------------------
1 | 1 | 2
2 | 3 | 4
3 | 2 | 1
I want to join tables so it shows the city name for both columns i.e: from_city_id & to_city_id
what i tried:
SELECT *
FROM tblflights
JOIN tblcities
ON tblflights.from_city_id = tblcities.id
result:
id | from_city_id | to_city_id | name
--------------------------------------------
1 | 1 | 2 | Bahawalpur
2 | 3 | 4 | Karachi
3 | 2 | 1 | Multan
but i want name of both cities (from_city_id & to_city_id)
i tried my best but could not found any solution.
i am using CodeIgniter

Try something like this.
SELECT tf.id, tc1.name from_city_name, tc2.name to_city_name
FROM tblflights tf
JOIN tblcities tc1
ON tf.from_city_id = tc1.id
JOIN tblcities tc2
ON tf.from_city_id = tc2.id;
You may need to remove duplicates depending on your table contents.

Related

MySQL - join multiple mapped tables and count records with different mapping conditions

It's the 3rd day I'm trying to write a MySQL query. Did lots of search, but it still doesn't work as expected. I'll try to simplify tables as much as possible
System has tkr_restaurants table:
restaurant_id | restaurant_name
1 | AA
2 | BB
3 | CC
Each restaurant has a division assigned (tkr_divisions table):
division_id | restaurant_id | division_name
1 | 1 | AA-1
2 | 1 | AA-2
3 | 2 | BB-1
Then there are meals in tkr_meals_to_restaurants_divisions table, where each meal can be assigned (mapped) to whole restaurant(s) and/or specific division(s). If meal is mapped to restaurant, all restaurant's divisions should see it. If meal is mapped to division(s), only specific division(s) should see it.
meal_id | mapped_restaurant_id | mapped_division_id
1 | 1 | NULL
2 | NULL | 1
3 | NULL | 2
I need to display a list of restaurants and number of meals mapped to it depending on user permissions.
Example 1: if user has permissions to access whole restaurant_id 1 and restaurant_3 (and no specific divisions), then list should be:
AA | 3
CC | 0
(because user can access meals mapped to restaurant 1 + all its division, and restaurant 3 + all its divisions (even if restaurant 3 has no divisions/meals mapped))
Example 2: if user has permissions to access only division_id 1, then list should be:
AA | 1
(because user can only access meals mapped to division 1).
The closest query I could get is:
Example 1:
SELECT *,
(SELECT COUNT(DISTINCT meal_id)
FROM
tkr_meals_to_restaurants_divisions
WHERE
tkr_meals_to_restaurants_divisions.mapped_restaurant_id=tkr_restaurants.restaurant_id
OR tkr_meals_to_restaurants_divisions.mapped_division_id=tkr_divisions.division_id)AS total_meals
FROM
tkr_restaurants
LEFT JOIN
tkr_divisions
ON tkr_restaurants.restaurant_id=tkr_divisions.restaurant_id
WHERE
tkr_restaurants.restaurant_id IN (1, 3)
OR tkr_restaurants.restaurant_id IN (
SELECT restaurant_id
FROM tkr_divisions
WHERE division_id IN (NULL)
)
GROUP BY
tkr_restaurants.restaurant_id
ORDER BY
tkr_restaurants.restaurant_name
However, result was:
AA | 2
CC | 0
I believe I'm greatly over-complicating this query, but all the simpler queries I wrote produced even more inaccurate results.
What about this query:
SELECT
FROM tkr_restaurants AS a
JOIN tkr_divisions AS b
ON a.restaurant_id = b.restaurant_id
LEFT OUTER JOIN tkr_meals_to_restaurants_divisions AS c
ON (c.mapped_restaurant_id = a.restaurant_id OR c.mapped_division_id = b.division_id)
As a Base four your further work. It combine all information into one table. If you add e.g. this:
WHERE a.restaurant_id IN (1, 3)
the result will be
| restaurant_id | restaurant_name | division_id | restaurant_id | division_name | meal_id | mapped_restaurant_id | mapped_division_id |
|---------------|-----------------|-------------|---------------|---------------|---------|----------------------|--------------------|
| 1 | AA | 1 | 1 | AA-1 | 1 | 1 | (null) |
| 1 | AA | 2 | 1 | AA-2 | 1 | 1 | (null) |
| 1 | AA | 1 | 1 | AA-1 | 2 | (null) | 1 |
| 1 | AA | 2 | 1 | AA-2 | 3 | (null) | 2 |
just count the distinct meal ids with COUNT(DISTINCT c.meal_id) and take the restaurant name to get AA: 3 for your example 2
I used a sqlfiddle: http://sqlfiddle.com/#!9/fa2b78/18/0
[EDIT]
Change JOIN tkr_divisions AS b to LEFT OUTER JOIN tkr_divisions AS b
Change SELECT * to SELECT a.restaurant_name, COUNT(DISTINCT c.meal_id)
Add a GROUP BY a.restaurant_name at the end.
Update the SQL Fiddle (new link)

Selecting multiple unrelated data from two tables and insert into one table mysql

This is my scenario
I have a permissions table with the following fields.
id | module | permission
1 | client | add
2 | client | edit
3 | client | delete
4 | someth | edit
5 | someth | delete
employee table
id | status | somestatus
1 | act | 1
2 | den | 1
3 | act | 0
4 | den | 1
5 | act | 0
6 | act | 1
Now what i would need to do is select the employee who have status="act" and somestatus=1 and give them all permissions where module="client"
so the table employee_permissions should have these rows
id | empid | permid | permvalue
1 | 1 | 1 | 1
2 | 1 | 2 | 1
3 | 1 | 3 | 1
1 | 6 | 1 | 1
2 | 6 | 2 | 1
3 | 6 | 3 | 1
This is the query I tried and I'm stuck here
INSERT INTO at2_permission_employee (employee_id,permission_id)
SELECT at2_employee.employee_id as employee_id
, (SELECT at2_permission.permission_id as permission_id
FROM at2_permission
where at2_permission.permission_module='client'
)
from at2_employee
where at2_employee.employee_status='Active'
and at2_employee.employees_served_admin = 1;
I get the error sub query returns multiple rows which makes sense to me. But I'm not sure how to modify the query to account for iterating over the rows returned by sub query
If I'm not wrong, like this:
INSERT INTO at2_permission_employee (employee_id, permission_id, permvalue)
SELECT
at2_employee.employee_id,
at2_permission.permission_id,
1
FROM at2_permission cross join at2_employee
WHERE
at2_employee.employee_status='Active'
and at2_employee.employees_served_admin = 1
and at2_permission.permission_module='client';
It's a bit unclear where the value for permvalue should come from so I hard coded it and used the permission.id for both id and permid, but this query should give you an idea on how to accomplish what you want:
insert employee_permissions (id, empid, permid, permvalue)
select p.id, e.id, p.id, 1
from employee e, permissions p
where p.module = 'client' and e.status = 'act' and e.somestatus = 1;

MySQL Select distinct row where one column is identical, and 2nd column is "3" or "4"

I have a table with data that looks something like this:
+------+--------+------------+
| id | Action | GeoDataID |
+------+--------+------------+
| 1 | 3 | 117085664 |
| 2 | 4 | 117085664 |
| 3 | 3 | 117096940 |
| 4 | 3 | 117096404 |
+------+--------+------------+
Now, I want to get all GeoDataID's that only has action = 3, and not action = 4. PS!! 1 and 2 have IDENTICAL GeoDataID and should not return row 1 in the result.
As you can see from id 1 and 2 they have identical GeoDataID.
From this example I want output only id 3 and 4. I've been trying to google, but can't find anything similar to what I want.
From the example above, the result should be:
+------+--------+------------+
| id | Action | GeoDataID |
+------+--------+------------+
| 3 | 3 | 117096940 |
| 4 | 3 | 117096404 |
+------+--------+------------+
1 and 2 not included due to GeoDataID 117085664 having Action 4.
You can exclude the items which have the same GeoDataID but Action 4 by introducing the 'negative criteria' with NOT EXISTS:
SELECT mt1.id, mt1.Action, mt1.GeoDataID
FROM MyTable mt1
WHERE mt1.Action = 3
AND NOT EXISTS
(
SELECT 1
FROM MyTable mt2
WHERE mt2.Action = 4
AND mt2.GeoDataID = mt1.GeoDataID
);
SqlFiddle here

How to display the string values of a table refering to Two foreign ID keys on the main table

So I have this database
TABLE: rates
ID | FID | TID | RATE
---------------------------
1 | 1 | 2 | 0.3
2 | 1 | 3 | 1.2
3 | 1 | 4 | 4.5
4 | 2 | 1 | 1.3
5 | 2 | 3 | 3.3
6 | 2 | 4 | 4.4
TABLE: currencies
ID | Name | Symbol
---------------------
1 | Euro | E
2 | Pound | P
3 | Dollar | $
4 | CAD | C
So what I tried so far was
SELECT rates.*,
currencies.name,
currencies.symbol FROM RATES
JOIN CURRENCIES ON
(rates.fid = currencies.id)
Which worked but only for 1 column. I could not find a way to add more. Also I want to give a custom output name for each currency. So the final output should be:
ID | FromCurrency (FID) | ToCurrency (TID) | Rate
You need to do multiple joins, and as you are using the same table for both joins, give them an alias.
Something like this:
SELECT rates.ID,
a.name AS 'FromCurrency (FID)',
a.symbol AS 'FID Symbol',
b.name AS 'ToCurrency (TID)',
b.symbol AS 'TID Symbol',
rates.rate
FROM RATES
JOIN CURRENCIES AS a ON
(rates.fid = a.id)
JOIN CURRENCIES AS b ON
(rates.tid = b.id)
Here is a working example

Mysql: return 0 when result 1 row in a table, other table result is 2 rows

How to display result
Temp | Order | Payment
A | 5 | 3
A | 4 | 0
B | 2 | 2
B | 0 | 3
C | 3 | 0
with: first_table:
Name | Description
A | Description A
B | Description B
C | Description C
second_table:
Name | order
A | 5
A | 4
B | 2
C | 3
third_table:
Name | Payment
A | 3
B | 2
B | 3
Meaning:
there are 2 order (value: 4,5) with Name=A.
there is 1 order (value: 3) with Name = A
And result I want to display:
Name | Order | Payment
A | 4 | 3 |
A | 5 | 0 |
Any help me?
You need to use JOIN.
From your example there is no Payment for order A5 so you should use LEFT JOIN which will result in Payment being NULL for that row (A5). LEFT JOIN basically means "select rows from first table and if there is no match in second table, put NULL".
Simply do a LEFT JOIN on second_table and third_table on field Name where Name=a. It's a very basic example so I won't give you the exact query, you should learn it by yourself.