Good day fellow programmers. I have 3 tables, with following sample records.
tbl_members has:
mem_id | mem_fname | mem_lname
1 | Ryan | Layos
2 | Dhave | Sebastian
3 | Staven | Siegal
4 | Ma Ethel | Yocop
5 | Kelvin | Salvador
6 | Herbert | Ares
tbl_member_status has:
status_id | mem_id | leader_id | process_id
1 | 2 | 1 | 2
2 | 3 | 5 | 3
3 | 4 | 6 | 4
4 | 5 | 1 | 4
5 | 1 | 6 | 4
(tbl_member_status.mem_id is foreign keyed to tbl_members.mem_id, and leader_id is also foreign keyed to tbl_members.mem_id because in my case a member can be a leader. 1 member 1 leader)
tbl_process has:
process_id | process_type
1 | CONSOLIDATION
2 | PRE-ENCOUNTER
3 | ENCOUNTER
4 | POST-ENCOUNTER
(a member has a process to take which i used enum with values: CONSOLIDATION, PRE-ENCOUNTER, ENCOUNTER, POST-ENCOUNTER, etc.)
My question now is the proper sql query in getting the desired output query like this.
tbl_query_result
mem_id | member_fname | member_lname | leader_fname | leader_lname | process_type
2 | dhave | sebastian | Ryan | Layos | PRE-ENCOUNTER
5 | Kelvin | Salvador | Ryan | Layos | POST-ENCOUNTER
do remember that two columns of tbl_member_status is referring to one column of tbl_members that is mem_id.
UPDATE:
what i have done so far:
SELECT member.mem_fname, member.mem_lname, leader.mem_fname, leader.mem_lname, tbl_process.process_type
FROM
tbl_member_status as mem_stats
INNER JOIN
tbl_members as member
INNER JOIN
tbl_members as leader
INNER JOIN
tbl_members ON mem_stats.member_id = member.mem_id
INNER JOIN
tbl_process ON tbl_process.process_id = mem_stats.process_id
WHERE
leader.mem_fname = 'Ryan'
This query gets all record even if the leader.mem_fname is not equal to 'Ryan'
Because when you query. The number of rows in the result matters. Like: if your result is for fname = ryan but then the match for mem.id in table memberstatus is two and then in process table is again two. Inshort you will have 2 rows in final output.
Can you try this :
Select M.member_fname, M.mem_lname P.process_type from tbl_members M, tbl_member_status MS, tbl_process P where M.mem_id = MS.mem_id and MS.process_id = P.process_id and where M.member_fname = 'ryan'
Okay i misunderstood your question at first. I have a solution for you which will improve your database schema. If one member has only one leader and a single leader has many memebers. Then why not create a different table called leader and connect to members table directly? So it will be a one to one relation. Which will make querying much simpler. So now you have 4 tables.
Select M.member_fname, M.mem_lname, L.fname, L.lname, P.process_type
from tbl_members M, tbl_member_status MS, tbl_process P, tbl_leader L
where M.leader_id = L.id and M.mem_id = MS.mem_id and MS.process_id = P.process_id and where M.member_fname = 'ryan'
Related
I have the following tables:
Student Table
| id | name | gender|
|----|----------|-------|
| 1 | April | F |
| 2 | Jane | F |
| 3 | Joe | M |
| 4 | Mike | M |
Project Table
| project_id | student_id | project_name|
|------------|------------|-------------|
| 101 | 1 | Alpha |
| 101 | 2 | Alpha |
| 101 | 3 | Alpha |
| 102 | 2 | M |
| 102 | 4 | M |
| 103 | 1 | Beta |
| 103 | 3 | Beta |
Assume there are much more students and project ids.
Multiple students can work in the same project.
My question is, having the tables above, how can I check how many students who worked together on 2 or more projects? So in the example above, students with id 1 and 3 worked together in project Alpha and Beta.
My code so far is
SELECT * FROM student s
JOIN project s ON student.id = project.project_id
I know I want to join both tables by the column they share (which is the student id) but I have no idea what to do after. I am new to SQL barely a week in learning and would appreciate the most help.
Use a self join and aggregation:
select p1.student_id, p2.student_id, count(*) as num_projects
from projects p1 join
projects p2
on p1.project_id = p2.project_id and
p1.student_id < p2.student_id
group by p1.student_id, p2.student_id
having count(*) > 1
order by count(*) desc;
Consider:
select count(*)
from (
select 1
from projects p1
inner join projects p2
on p2.project_id = p1.project_id and p2.student_id < p1.student_id
group by p1.student_id, p2.student_id
having count(*) > 1
) t
The inner query self-joins the project table and generates unique tuples of students that worked on the same project; the having clause filters on tuples that worked together on more than one project.
The outer query just counts the number of tuples.
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)
I don't know if a similar question have been asked, but I looked fow more than hour on mysql in stackoverflow
My problem is, i have multiple tables and I need to join them with both left join and inner join in mysql
Entity table :
id (key) | entityName
1 | john
2 | harris
3 | henry
4 | mark
5 | dom
Activity table
id (key) | entityID | status
1 | 1 | 1
2 | 2 | 0
3 | 4 | 1
Geodata table
id (key) | entityID | moment (timestamps when the entry was done)
1 | 1 | 1429542320 (smaller)
2 | 1 | 1429542331 (bigger)
3 | 2 | 1429542320 (smaller)
4 | 2 | 1429542331 (biger)
5 | 4 | 1429542331 (bigger)
Info table
id (key) | entityID | infos | date
1 | 1 | xxx | today
2 | 1 | xxx | yesterday
3 | 2 | xxx | today
4 | 2 | xxx | yesterday
5 | 3 | xxx | yesterday
6 | 5 | xxx | today
7 | 5 | xxx | yesterday
8 | 5 | xxx | tomorrow
So basically, I need every Entities that has an info for today
Moreover, if their status is true (or 1) (from activity table), show me their date in geodata table.
So this is what i've got :
SELECT e.id,
e.entityName,
i.infos,
a.status,
MAX(g.moment) -- but the max only if status =1
FROM entities AS e
LEFT JOIN activity AS a ON a.entityID = e.id
LEFT JOIN geodata AS g ON g.entityID = e.id
INNER JOIN infos AS i ON e.id = i.entityID
WHERE i.date = 'today'
GROUP BY e.id
I want every entities that has an info about today, but some of them have activity too, so i want to show it (if it doesn't just let the left join put NULL) If the status is 0, I don't need the moment, but if its true, I only need the bigger one (its numbers, so Max() should do it but it breaks)
The expected results is :
id (key) | entityName | infos | status | MAX(moment) | ..other columns
1 | john | xxx | 1 | 1429542331 (the bigger one)
2 | harris | xxx | 0 | NULL
5 | dom | xxx | NULL | NULL
If someone can help me, I'll be very thankful :)
PS.: Sorry for my english, it isn't my first language
You could change the
MAX(g.moment)
to
IF(a.status<>1, NULL, MAX(g.moment))
or alternately change LEFT JOIN geodata AS g ON g.entityID = e.id to LEFT JOIN geodata AS g ON a.entityID = e.id AND a.status = 1
Which one is faster will probably depend on your actual data; the second may be faster as less records are joined, but the more complicated join condition it uses might slow down the joining.
I have a question about FULL JOIN at MySql. I know that alternative is UNION but I have dificulties to combine them all.
I guess it would be already enough to get answer on 4 tables as 5th and 6th are same as in first 4.
Tables: Bill, Service, BS, Item, BI, Buyer
BS connect more Services to Bill and BI connect more Items to Bill. Buyer is 1:1 relation with Bill.
Tables example:
Bill:
----------------------
id | number | Buyer_id
1 | 12014 | 3
2 | 22014 | 2
3 | 32014 | 5
Services:
----------------------
id | cost
1 | 2
2 | 7
3 | 1
4 | 12
BS:
----------------------
id | Bill_id | Services_id
1 | 1 | 3
2 | 1 | 4
3 | 2 | 2
4 | 3 | 1
5 | 3 | 2
6 | 3 | 3
7 | 3 | 4
Item:
----------------------
id | cost
1 | 34
2 | 77
3 | 2
4 | 15
5 | 13
BI:
----------------------
id | Bill_id | Items_id
1 | 1 | 5
2 | 2 | 3
3 | 3 | 2
Buyer:
----------------------
id | name
1 | John
2 | Mary
3 | Dave
4 | Carl
5 | Jack
So far the closest I got to was that I used following SQL:
SELECT *
FROM Bill b
LEFT JOIN BI ON BI.Bill_id = b.id
LEFT JOIN BS ON BS.Bill_id = b.id
LEFT JOIN Item i ON i.id = BI.Item_id
LEFT JOIN Services s ON s.id = BS.Services_id
LEFT JOIN Buyer ON Buyer.id = b.Buyer_id
WHERE b.number = '12014'
Result gives me 2 Services and 1 duplicated Item but I want one Item and one NULL item (as only one item is attached to that bill.
Result that I get (just ids as it's shorter):
b.id | s.id | BS.id | i.id | BI.id | Buyer.id
1 | 3 | 1 | 1 | 5 | 3
1 | 4 | 2 | 1 | 5 | 3
And desired result in table:
b.id | s.id | BS.id | i.id | BI.id | Buyer.id
1 | 3 | 1 | 1 | 5 | 3
1 | 4 | 2 | NULL | NULL | 3 (or NULL, doesn't really matter)
I tried with others as well but I got even more rows than 2 (note that two are expected or if Bill.number=32014 then 4 rows).
Thank you!
You are taking the wrong approach.
The result of a query to a relational database is a relation - you may treat it as a rectangular matrix with rows and columns. Every row represents something (at least it should), every column represents an attribute and every cell represents the thing's attribute's value.
| [attr 1] | [attr 2]
-----------+---------------+-------------------------
[thing 1] | value | some value
[thing 2] | value | other value
[thing 3] | a value | yeah, a value
Now here is what you are trying to produce:
| [attr 1] | [attr 2] | | [other attr 3]
-----------+---------------+------------------+---------------------+-------------------
[thing 1] | value | some value | [other thing 1] | a value
[thing 2] | value | other value |
See? Attempting to return two relations with a single query. Not rectangular anymore, huh? Items and services are independent here, but you are trying to put them into a single row. Don't go this way, here are three queries for you:
-- Get bill/buyer details (1 row)
SELECT b.id, Buyer.id
FROM Bill b
LEFT JOIN Buyer ON Buyer.id = b.Buyer_id
WHERE b.number = '12014';
-- Get billed items (1 row per item)
SELECT BI.id, i.id
FROM Bill b
JOIN BI ON BI.Bill_id = b.id
JOIN Item i ON i.id = BI.Item_id
WHERE b.number = '12014';
-- Get billed services (1 row per service)
SELECT BS.id, s.id
FROM Bill b
JOIN BS ON BS.Bill_id = b.id
JOIN Services s ON s.id = BS.Services_id
WHERE b.number = '12014';
Note that item and services queries don't use left joins. You would like to return 0 rows if there are no items/services on the bill.
Then handle the results of them one by one in your application.
Edit:
Sometimes two (or more) entities share some common characteristics, for example in your application you could treat services and items as bill lines. In this case, this could be valid to retrieve all of them in a single query, but only this way using union:
-- Get bill lines (items and services)
SELECT BI.id AS bill_item_id, i.id AS item_id, NULL as bill_service_id, NULL as service_id
FROM Bill b
JOIN BI ON BI.Bill_id = b.id
JOIN Item i ON i.id = BI.Item_id
WHERE b.number = '12014';
UNION ALL
SELECT NULL AS bill_item_id, NULL AS item_id, BS.id as bill_service_id, s.id as service_id
FROM Bill b
JOIN BS ON BS.Bill_id = b.id
JOIN Services s ON s.id = BS.Services_id
WHERE b.number = '12014';
Which will return a result similar to what you originally expected:
BI.id | i.id | BS.id | s.id
5 | 1 | NULL | NULL
NULL | NULL | 1 | 3
NULL | NULL | 2 | 4
Note that:
each item and service is an individual bill line represented by a record. Don't try to artificially "compress" data across rows or columns
it's not the case in your schema, but most often there are also some shared attributes, like line id, quantity ordered or amount paid.
Lets say, I have two tables - people and bonus
------------
people
------------
people_id | company_id | job_id
1 | 1 | 2
2 | 1 | 4
3 | 2 | 1
4 | 2 | 3
5 | 3 | 5
------------
bonus
------------
job_id | bonus_id
1 | 101
2 | 102
3 | 103
Now, I want to have a joined table like the following
-------------
JOINED TABLE
-------------
people_id | company_id | job_id | bonus_id | no_of_bonus_for_company
1 | 1 | 2 | 102 | 1
2 | 1 | 4 | NULL | 1
3 | 2 | 1 | 101 | 2
4 | 2 | 3 | 103 | 2
5 | 3 | 5 | NULL | 0
I need to have the main search term in people_id as in -
SELECT p.people_id,
p.company_id,
p.job_id,
b.bonus_id
FROM people p
LEFT JOIN bonus b
ON p.job_id = b.job_id
WHERE p.people_id IN (1,2,3,4,5)
ORDER BY p.people_id ASC;
But how do I get the fifth column of the joined table? It actually counts the no. of bonus id's for each company id in the joined table itself.
I can only assume that you are telling us part of the picture so I will reserve judgement about the DB schema, normalization etc.
Given the presented facts you can retrieve the information in the following manner.
NOTE : This is TSQL syntax but I don't think that the mySQL syntax should be very different i.e. ISNULL -> IFNULL
SELECT p.people_id
, p.company_id
, p.job_id
, b.bonus_id
, ISNULL((
SELECT COUNT(pt.Job_Id)
FROM Bonus bt
INNER JOIN People pt
ON pt.job_Id = bt.job_Id
WHERE pt.company_Id = p.company_Id
GROUP BY pt.company_Id
), 0) AS no_of_bonus_for_company
FROM People p
LEFT JOIN Bonus b
ON p.job_Id = b.job_Id