Update two or more table - php

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)

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.

How to fetch data from database comparing some value using PHP and Mysql

I have some doubt. Actually i need to fetch data as per column value by joining two table using PHP and MySQL .I am explaining my tables below.
db_specials:
id special type
1 Food and Beverage 1
2 Liquor 2
db_basic:
id special_id name
1 2 aaa
2 1 Raj
3 2 Ram
4 2 Jay
5 1 Nikesh
Here i need to fetch all data from the tables db_basic those are associated with Liquor from first table. I am explaining my code below.
$res=mysqli_query($connect,"select b.id,b.special_id,b.name,s.type from db_basic as b inner join db_specials as s on b.special_id=s.id where b.special_id=2 order by b.id desc");
while($row=mysqli_fetch_array($res)){
$data[]=$row;
}
I am getting also the proper data. Here problem is db_specials also has the delete functionality on front end with insert. Suppose user deleted the row which has id=2 in db_specials table and insert again,in this case the id will change 2 to 3. So the query also needs to change accordingly. Here i need to know what should be the best logic so that each time user will not change the query if any specials is deleted and inserted again. Please help me.
Instead of id column, you should rely on the type column of db_specials table, since it's not going to be auto incremented for each INSERT operation. So your query should be like this:
select b.id,b.special_id,b.name,s.type
from db_basic as b
inner join db_specials as s
on b.special_id=s.type
where b.special_id=2
order by b.id desc
Also, I recommend that you should change the special_id column name of db_basic table to type, like this:
+------+------+------+
| id | type | name |
+------+------+------+
| | | |
This way, it would be easier for you to construct the query, like this:
select b.id,b.type,b.name
from db_basic as b
inner join db_specials as s
on b.type=s.type
where b.type=2
order by b.id desc
if user deleted 2,Liquor,2 in db_specials and reinsert, you cannot control what the user input in the front end.
User might be insert Food,2
Instead of join the type column of db_specials with db_basic, you should put a checking in the front end, when user click the delete button, prompt a message before delete 2,Liquor,2 from the table db_specials, if there is any special_id=2 in table db_basic the corresponding rows will deleted as well.

PDO and prepared statements on dynamic sized queries

I am developing a small gaming website for college fest where users attend few contests and based on their ranks in result table, points are updated in their user table. Then the result table is truncated for the next event. The schemas are as follows:
user
-------------------------------------------------------------
user_id | name | college | points |
-------------------------------------------------------------
result
---------------------------
user_id | score
---------------------------
Now, the first 3 students are given 100 points, next 15 given 50 points and others are given 10 points each.
Now, I am having problem in developing queries because I don't know how many users will attempt the contest, so I have to append that many ? in the query. Secondly, I also need to put ) at the end.
My queries are like
$query_top3=update user set points =points+100 where id in(?,?,?);
$query_next5=update user set points = points +50 where id in(?,?,?,?,?);
$query_others=update user set points=points+50 where id in (?,?...........,?);
How can I prepare those queries dynamically? Or, is there any better approach?
EDIT
Though its similar to this question,but in my scenario I have 3 different dynamic queries.
If I understand correctly your requirements you can rank results and update users table (adding points) all in one query
UPDATE users u JOIN
(
SELECT user_id,
(
SELECT 1 + COUNT(*)
FROM result
WHERE score >= r.score
AND user_id <> r.user_id
) rank
FROM result r
) q
ON u.user_id = q.user_id
SET points = points +
CASE
WHEN q.rank BETWEEN 1 AND 3 THEN 100
WHEN q.rank BETWEEN 4 AND 18 THEN 50
ELSE 10
END;
It totally dynamic based on the contents in of result table. You no longer need to deal with each user_id individually.
Here is SQLFiddle demo

How to optimize a score/rank table with different specific scores and ranks?

in our project we've got an user table where userdata with name and different kind of scores (overall score, quest score etc. is stored). How the values are calculated doesn't matter, but take them as seperated.
Lets look table 'users' like below
id name score_overall score_trade score_quest
1 one 40000 10000 20000
2 two 20000 15000 0
3 three 30000 1000 50000
4 four 80000 60000 3000
For showing the scores there are then a dummy table and one table for each kind of score where the username is stored together with the point score and a rank. All the tables look the same but have different names.
id name score rank
They are seperated to allow the users to search and filter the tables. Lets say there is one row with the player "playerX" who has rank 60. So if I filter the score for "playerX" I only see this row, but with rank 60. That means the rank are "hard stored" and not only displayed dynamically via a rownumber or something like that.
The different score tables are filled via a cronjob (and under the use of a addional dummy table) which does the following:
copies the userdata to a dummy table
alters the dummy table by order by score
copies the dummy table to the specific score table so the AI primary key (rank) is automatically filled with the right values, representing the rank for each user.
That means: Wheren there are five specific scores there are also five score tables and the dummy table, making a total of 6.
How to optimize?
What I would like to do is to optimize the whole thing and to drop duplicate tables (and to avoid the dummy table if possible) to store all the score data in one table which has the following cols:
userid, overall_score, overall_rank, trade_score, trade_rank, quest_score, quest_rank
My question is now how I could do this the best way and is there another way as the one shown above (with all the different tables)? MYSQL-Statements and/or php-code is welcome.
Some time ago I tried using row numbers but this doesn't work a) because they can't be used in insert statements and b) because when filtering every player (like 'playerX' in the example above) would be on rank 1 as it's the only row returning.
Well, you can try creating a table with the following configuration:
id | name | score_overall | score_trade | score_quest | overall_rank | trade_rank | quest_rank
If you do that, you can use the following query to populate the table:
SET #overall_rank:=-(SELECT COUNT(id) FROM users);
SET #trade_rank:=#overall_rank;
SET #quest_rank:=#overall_rank;
SELECT *
FROM users u
INNER JOIN (SELECT id,
#overall_rank:=#overall_rank+1 AS overall_rank
FROM users
ORDER BY score_overall DESC) ovr
ON u.id = ovr.id
INNER JOIN (SELECT id,
#trade_rank:=#trade_rank+1 AS trade_rank
FROM users
ORDER BY score_trade DESC) tr
ON u.id = tr.id
INNER JOIN (SELECT id,
#quest_rank:=#quest_rank+1 AS quest_rank
FROM users
ORDER BY score_quest DESC) qr
ON u.id = qr.id
ORDER BY u.id ASC
I've prepared an SQL-fiddle for you.
Although I think performance will weigh in if you start getting a lot of records.
A bit of explanation: the #*_rank things are SQL variables. They get increased with 1 on every new row.

Twitter-like following system

I am working on a twitter clone in PHP for school, and I have one major problem. I cannot find a way to implement a follower system. There is a table for users, and I want to add a field that holds the ids of all of the users that each user follows.
Should I separate the ids with commas and then split them apart in PHP? And then I need to select all of the tweets from the tweets table that were tweeted by any of the users followers. Is there an SQL command that I can use? Something similar to
SELECT *
FROM tweets
WHERE author='$followeduser'"
but where $followeduser is multiple ids.
Have a USER_MASTER table like this
USER_ID (int)
USER_NAME(varchar(50))
Create a table called USER_FOLLOWERS like this
USER_FOLLOWER_ID // Auto increment-Primary Key for this record
USER_ID (int) // foriegn key to UserId column in USER_MASTER table
FOLLOWER_ID (int) // foriegn key to UserId column in USER_MASTER table
Store the UserId in the first column and store the UserId of the User who follows this user in the Follower_ID column.
So your data will look like this
USER_ID USER_NAME
--------------------------------------
1 SCOTT
2 JARED
3 MARC
4 ERIC
USER_FOLLOWER_ID USER_ID FOLLOWER_ID
--------------------------------------
1 1 2
2 1 3
3 1 4
4 2 1
So this means , The User Scott has 3 followers, Jared, Marc and Eric. User JARED HAS one Follower, that is SCOTT
To get the list of Followers for a user(ex : Scott (ID=1)) , you can do a Join between these 2 tables
SELECT U. USER_ID, U.USER_NAME From USER_MASTER U
INNER JOIN USER_FOLLOWERS UF ON U.USER_ID=UF.FOLLOWER_ID
WHERE UF.USER_ID=1 // 1 is the ID of SCott
Make a join table.
Putting all IDs in a list is not the normalized way and can lead to many many issues.
Have a relations table where you have one column called user and second that is following. So if user 1 is following user 3 and 5, then you would have an entree where user = 1 following = 3 and user = 1 following = 5 (use whatever ID's you want). You also have your Tweets Table where you store all tweets. Youre going to want to make a query that joins the two tables

Categories