Mysql Php combining 3 tables - php

basically in this web app i have an event module where user can create, edit and delete an event also can upload photo for that event. Other users either can involve in particular event by selecting I'm in button or just mentioning the event Sound's Cool.
For now there is 3 tables event_photo (user upload pic will be saved here), event_in and event_cool, now i need an event activity feed, for that i need to combine all 3 tables by grouping them as photo, in and cool. So i need suggestion whether to create a single table to list these activity or should i combine all the results in php. Previously i combine all 2 results in single table but now i want to try something different. There are the table structure.
event_photo table
id photo_url business_id event_id user_id caption added_date
1 1111 12 2 3 test1 20130209t1
2 1122 13 3 4 test2 20130209t4
3 1133 14 2 3 test3 20130209t2
event_in table
id event_id user_id date_created
1 2 3 20130209t3
event_cool
id event_id user_id date_created
1 2 4 20130209t5
2 3 3 20130209t6
Now the feed will be like this, based on date_created desc t6 -> t1
User_3 says cool for Event_3
User_4 says cool for Event_2
User_4 added photo for Event_3
User_3 added photo for Event_2
User_3 attending Event_2
User_3 added photo for Event_2
User_3 added photo for Event_2
Now how the table should be design, i hope this is important questions as this can resolve many problems regarding activity feed.Thanks

An option would be to have your three tables and query them with something similar to:
SELECT *
FROM
( SELECT user_id,
event_id,
date_added as date_created,
'photo' as type
FROM event_photo
UNION
SELECT user_id,
event_id,
date_created,
'event_in' as type
FROM event_in
UNION
SELECT user_id,
event_id,
date_created,
'event_cool' as type
FROM event_cool
) s
ORDER BY date_created
To simplify your code, you could create a view:
CREATE OR REPLACE VIEW v_ordered_actions AS
SELECT *
FROM
( SELECT user_id,
event_id,
date_added as date_created,
'photo' as type
FROM event_photo
UNION
SELECT user_id,
event_id,
date_created,
'event_in' as type
FROM event_in
UNION
SELECT user_id,
event_id,
date_created,
'event_cool' as type
FROM event_cool
) s
ORDER BY date_created;

You can use UNION of course: http://dev.mysql.com/doc/refman/5.1/en/union.html However, this is quite slow. Maybe better to create next table, like activity log, where to store just:
entity_type (in/cool/photo)
entity_id (id of row in target table)
event_id
user_id
date
And select via this. When you have selected that, collect all IDs seperatelly for each target table, and get necessary info from that tables (if necessary) returned as indexed array. Foreach activity feed and assign correct data you need for it.
Hope this can help you.

Related

How to select particular column from table if another column includes all the set of requested values?

I have a table in MySQL named table1 which has three columns id, user_id(foreign_key) and destination_id(foreign_key). One user can have multiple destinations.
E.g Table1
id user_id destination_id
1 10 2
2 5 3
3 10 4
4 10 5
5 9 10
6 5 12
7 8 2
I get a request from the client side in PHP script; the request includes destination ids in an array.
E.g. $request = array('destination_id' => [2,4,5]);
I just want to get all the user_id from table1 if and only if the particular user_id contains all requested destinations.
I tried to achieve this using 'IN' operator.
i.e.
SELECT user_id FROM table1 WHERE destination_id IN ($requestedDestinationsInCommaSeparatedString)
It gives row including user_id 8 along with user_id 10 but I just need user_id 10. I just wanted to know the concept regarding the solution to the following problem. I am a beginner in SQL, any help would be very appreciable. Thanks.
You can check that a user_id refers to all requested destination by grouping and counting the destinations.
SELECT user_id
FROM table1
WHERE
destination_id IN (2,4,5)
GROUP BY
user_id
HAVING count(*) = 3
-- count must be the number of elments in (2,4,5)
For doing so, the field combination of user_id and destination_id must be unique over all records.
The only thing I can think of is to use multiple subselects and build the query string in PHP.
So for your specific example the SQL-Query-String generated should be
SELECT user_id
FROM table1
WHERE user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 2)
AND user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 4)
AND user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 5)
GROUP BY user_id
I think programming the function which generates the middle part for you shouldn't be too hard.

Update two or more table

i have three tables.
1st table is tbl_user
id u_name p_list
1 demo1 1,3,
2 demo2 4,3,1,
3 demo3 2,3,
4 demo4 2,5,
Second table is tbl_product
id product_name
1 example1
2 example2
3 example3
4 example4
5 example5
third table is tbl_order_list that show the list of order to the users. tbl look like
id pid uid
1 1 1,2,
2 4 2,
3 3 1,2,3,
4 5 4,
now i want
if i'll update tbl user means if i'll remove pid of column p_list of tbl_user than tbl_user will be updated and also tbl_order_list is update
"Example" if i'll remove 3 in p_list of id 2 from tbl_user than table is look like
id u_name p_list
1 demo1 1,3,
2 demo2 4,1, //(pid =3 is remove of demo2)
3 demo3 2,3,
4 demo4 2,5,
And tbl_order_list is look like
id pid uid
1 1 1,2,
2 4 2,
3 3 1,3, //(uid =2 is remove)
4 5 4,
what is the solution of this problem. i want also if i'll add again pid = 3 in p_list of id = 2 of table user than table look like previous tables.
QUERY (From Comments)
mysql_query("UPDATE tbl_user SET u_name='$userName',slug='$userSlug',password='$userPassword',email='$use‌​rEmail',role='$userRole',p_list='$userList',status='$userStatus',modified_‌​date='$userDate' WHERE id='$uId'");
Help Me
So far, I'm not seeing any real correlation to php, but whatever.
I would highly suggest using a normal form (see database normalization) and deduplicate your data. tbl_order_list is a very bad table, as is tbl_user. tbl_order_list shouldn't have an id field, the uid field should contain exactly one uid and the primary key should be (pid,uid) (so both fields). By that point it should be called tbl_order. If you want a list of all pids for a uid or all uids for a pid - at some point - you can query like this:
SELECT GROUP_CONCAT(uid)
FROM tbl_order
WHERE pid=[your pid of interest]
GROUP BY pid
and vice-versa (replace uid with pid and pid with uid). If you want to query it at the same time with the rest of your userdata:
SELECT u.*, GROUP_CONCAT(o.pid)
FROM tbl_user u
LEFT JOIN tbl_order o ON (u.id=o.uid)
[WHERE u.id=[your uid of interest]]
GROUP BY u.id
(and similarly with the tbl_product).
When using mysql >= 5.7 you can create a view:
CREATE VIEW tbl_order_list AS SELECT pid, GROUP_CONCAT(uid) FROM tbl_order GROUP BY pid.
Adding or Removing an order then would result in deleting/inserting a row in tbl_order.
Summary: Make a table tbl_order (uid,pid) that contains the links between uids and pids (one link per row). Join this table in, when you need the the links. Please don't save "references" as a comma-separated list in a string field unless there is a very very very good reason.
If you infact have a very very good reason, consider adding comma (,) to the beginning and end of your lists, meaning. So:
id pid uid
1 1 ,1,2,
2 4 ,2,
3 3 ,1,2,3,
4 5 ,4,
This way you can safely search, add, remove entries:
SELECT * FROM tbl_order_list WHERE uid LIKE '%,[uid of interest],%'
UPDATE tbl_order_list SET uid=CONCAT(uid,',',[uid to add]) WHERE id=[order to update]
UPDATE tbl_order_list SET uid=REPLACE(",[uid to remove],",",",uid) WHERE id=[order to update]
(and similar for your tbl_user, if you're querying by pid in the tbl_order list, drop the id field.)
If you don't prepend a comma, you might at some point have some problems with consistency.
Anyway, I cannot stress this enough: normalize your database structure unless you have very good reasons not to (and be absolutely sure, they really are good reasons, because usually they aren't)

MYSQL query to exclude records in specific condition

Hey I have the following MYSQL DB structure for 3 tables with many to many relation. Many users can have many cars and cars can be for many users as showing below:
Users
ID | Name
---------
100|John
101|Smith
Cars
ID | Name
---------
50|BMW
60|Audi
Users_cars
ID | UID | CID
---------
1| 100 |50
2| 100 |60
3| 101 |60
I have a page users_cars.php this page have two drop down lists
list of all users
list of all cars
In this page you can select a user from user's list and select a car from car's list then click add to insert into users_cars table.
What am trying to do is to exclude from user's drop down list all the users that have been linked with all the available cars from cars table.
In the example above user's drop down list will just have "Smith" because "John" linked with all cars available (BMW,AUDI), if "Smith" also has the BMW he will be excluded from the list. I need a select query for this condition and i don't want to use any nest select query to count user records inside users_cars table
If I understand what you are after you need to use GROUP BY in your query. So to select all users:
SELECT ID, UID FROM Users_cars GROUP BY UID
and for all cars:
SELECT ID, CID FROM Users_cars GROUP BY CID
That will group results that are the same, so you only get one instance of each user, or one instance of each car.
I hope I understood your question right.
I think you can so this using some programming -
With PHP/mysql -
Get count of all distinct car ID's
Get count of cars for each user. (making sure this lists only unique car ID's)
Loop through all users and in each loop compare the above two and exclude the user where this condition matches.
SELECT *
FROM users
WEHRE id NOT IN (SELECT uid
FROM (SELECT uid, COUNT(cid), COUNT(*)
FORM cars
LEFT OUTER JOIN users_cars ON cars.id = users_cars.cid
GROUP BY uid
HAVING COUNT(cid) = COUNT(*)
Basically, what you want to do is that (if I understood your problem) :
SELECT UID FROM Users_cars WHERE CID NOT IN (SELECT ID FROM Cars);
But carefull, this is a greedy request (depends on the size of the tables of course) and you should better put a flag on the user table and update then when your user uses the last available car (or with a batch) so you don't run the request too often !

compare two table result on based of count of column of second table

I am using mysql database.
I have two table one is user_songs and second is user_like
Fields of user_song:
id(auto incement)
song_id
user_id
song_name
song_file
Fields of user_like:
id(auto incement)
song_id
uder_id
like
In user_like I am saving data where any user going like song so each row contain data like:
1 1 1 1
Please note like saves either 0 or 1.0 for dislike and 1 for like.
Now I need to find out top 20 most like songs id from user_like and get all data from user_songs from user_songs.
How to do this?
Thanks in advance to spend your valuable time to solve this query.
SELECT a.*, b.totalLike
FROM user_song a
INNER JOIN
(
SELECT song_id, COUNT(*) totalLike
FROM user_like
GROUP song_id
) b ON a.song_id = b.song_ID
ORDER BY totalLike DESC
LIMIT 20
Caution: the query above doesn't handle tie up values on totaluserLike result. It will only display 20 records on the result list.

combining 2 tables in MySQL select statement

I know I can do joins but its not exactly what I want.
I'm making a live chat system that has 2 tables mainly: the main chat table (call it table a), and then a mod table (call this one table b). If a user gets suspended, messages reach over 100 for that channel, or they are over 1 week, the messages get moved from the main chat table to the mod table.
I store the ID of the chat messages as ID(primary) on the main chat table and as chatID on the mod table.
What I'm doing is making a separate page for my Mods and I want to be able to combine the two tables into 1 area but I want them to be ordered by their respective tables.
So lets say we had the following:
Main table ID's: 1,2,4
Mod table ID: 3
I want my results to show up 1,2,3,4 no matter which table the ID is in.
Any help is greatly appreciated!
Edit: I got the answer and this is what I used to do so:
SELECT ab.* FROM
((SELECT ID as table_id FROM a
WHERE roomID = 'newUsers' ORDER BY ID ASC)
UNION ALL
(SELECT chatID as table_id FROM b
WHERE roomID = 'newUsers' ORDER BY chatID ASC)) ab
ORDER BY ab.table_id
Use a UNION in a subselect.
SELECT ab.* FROM (
SELECT 1 as table_id, * FROM a
UNION ALL
SELECT 2 as table_id, * FROM b
) ab
ORDER BY ab.id
If you want the result of table A to appear before table B, change the query to:
SELECT ab.* FROM (
SELECT 1 as table_id, * FROM a
UNION ALL
SELECT 2 as table_id, * FROM b
) ab
ORDER BY ab.table_id, ab.id
Some background
UNION ALL will merge two tables resultsets into one resultset.
UNION will do the same but will eliminate duplicate rows.
This takes time and slows things down, so if you know there will be no duplicate records (or you don't care about dups) use UNION ALL.
See also: http://dev.mysql.com/doc/refman/5.5/en/union.html

Categories