mySQL data unique for each user - php

I am building an application using MySQL/cakePHP which involves the following requirements.
Admins create steps which users need to complete. e.g. yes/no type questions. Admins create these steps and new users should get them.
Users are required to complete all these steps when they logon.
My question is what would the best way to do this in the database (mySQL)
When a user signs up it queries the steps table and creates the new rows for each step for that user? It creates the rows from the server side code by looking in the steps table?
Create a new interim table to store to relationship??
I'm fairly experienced around relational design but a little stumped on the best way to do this and future proof myself at the same time.
**Mock Structure**
Steps
id
name
order
desc
**Users**
id
username
**Step_Users**
step_id
user_id
result1
result2
result3

Basically your tables are fine. Here is one scenario: Someone signs up. You take all the steps from table Steps and create a form with this fields. The user fills the form and submits them. Then you write those answers to a step_user table. And somehow you keep info that the user has finished the answers (probably another field somewhere or just check if there are rows for him in the step_user table). Of course that there are different approaches to handle this, based on the exact needs you have. Because you did not mentioned more details, I could mention more scenarios here but not sure if they will help.
If you like to be sure that each user has unique data for each step then from the table step_user you should make a composite unique index over the columns step_id and user_id http://www.w3schools.com/sql/sql_unique.asp, but of course you also need code to check this.

This is how I would design this too. Just, to cater for different amounts of steps (questions) later, perhaps save the Steps as one record per question, and do the same for the Step_users table:
**Step_Users**
step_id
user_id
result
If needed you can add a flag to the Users table which is set when the user completed all steps.

I would break it down this way:
You have, I assume, one row in the Steps table for each step in the process. You have one row in the Users table for each user in the system. Thus, your number of rows in the Step_Users table should be (rows in Steps) * (rows in Users).
I would recommend putting a boolean value into the Users table which is steps_finished. That way, you can know in an instant, just from pulling from the users table, whether or not they've been marked as finished. Also, future changes to the steps won't affect the user unless you want it to.
Follow this step when registering or logging in:
User registers a new account: steps_finished = false OR User logs in to an account.
If steps_finished = true, then ignore the rest of this. If false, continue.
System does a select * from Step_Users where user_id=X order by step_id
System does a select * from Steps order by id
Count through the rows in step 3 and compare them to the rows in step 2. When you find a row in step 3 that is not in the rows in step 2, give them that step. ( if you get through the entire table from step 3 and none are missing from the rows in step 2, then go set steps_finished = true )
NEXT PAGE SUBMISSION
Once they give a result for that step, select * from Step_Users where user_id=X and step_id=Y
If that result comes back as 0 rows returned, then you know they haven't submitted this step before. `insert into Step_Users (step_id, user_id, result1, result2, result3) values (X, Y, 'response1', 'response2', 'response3')
Do steps 3-5 above again.
There's many reasons to check the rows in the tables against each other' but the biggest is that the user might stop doing the steps in the middle, and you'll need a way to jump right back in where they started.

Related

Mysql multiple updates in one statement

So the situation I have is this. I have 2 tables one for users and the other stores email(s) for those users. The email table is related to users by a foreign key user_id. I am trying to set up an archive system where the user can archive these users and keep them in the production db. But I need to delete the original and re-insert the user to give them a new id. This way they can archive again later and the data won't be corrupt and any new information will then be archived also. This is just a small example I am actually doing this with 10 tables, some of them related to each other. The amount of data that is involved can be quite large and when the archive starts it can take several minutes to complete because for every user I am also checking, archiving, deleting and re-inserting that user. The way I have it set up now there can be literally several 1000 queries to accomplish the complete archive.
So I am trying to re-write this so that the number of query calls is limited to one. By getting all the users, looping through them and building an insert query where I can insert many records with one call. Everything is great for the users but when I want to do this for their emails I run into an issue. As I'm looping through the users I save the id (the original id) to an array, hoping to use it later to update the new email records with the new user_id that was created. I can get the first id from my big insert and I know how many records there were so I know all the new id's. I can set up a for loop to create a new array with the new id's thereby matching the original id array.
So the question is, is there a way to set up an update statement that would allow for a multiple update statement in one call? The indexes from the two arrays will match.
update email_table
set user_id = {new_id_array}
where user_id = {old_id_array}
I have seen several different option out there but nothing that quite does what I'm trying to do. Any help is very much appreciated.
The simplest way to do what you need I think is to have some table containing old_id <-> new_id relations.
Once you have that data somewhere in your database you just need to join:
https://www.db-fiddle.com/f/bYump2wDn5n2hCxCrZemgt/1
UPDATE email_table e
JOIN replacement r
ON e.user_id = r.old_id
SET e.user_id = r.new_id;
But if you still want to do something with plain lists you need to generate query to manipulate with ELT and FIELD:
https://www.db-fiddle.com/f/noBWqJERm2t399F4jxnUJR/1
UPDATE email_table e
SET e.user_id = ELT(FIELD(e.user_id, 1, 2, 3, 5), 7, 8, 9, 10)
WHERE e.user_id IN (1,2,3,5);

configure mysql database to save progress

I am new in forum, and need some help to do one functionality for my unity game. I am trying to save the progress of the player in one mysql database, like this:
userid level stars
29 1 2
29 2 1
45 1 3
50 1 2
50 2 3
50 3 1
29 3 3
so the script send the userid provided by the user registration in the begining of the game. and for each level he complete, the script send the number of the level, and the amount of stars collected in the level..
the problem and question is, how I configure this in the php script and mysql database to save the information only once? because if the player with the id 50 play the first level, will add a line with the information, but if the same player play the first level again and change the amount of stars, I dont want a new line, just update the stars amount.
I take a look in the INDEX, UNIQUE, PRIMARY, FULLTEXT, SPATIAL functions but dont figured out what is the correct combination and how to put in the php script, and take a look in other questions in the forum but nothing like this.
thanks for the help!
I recommend you use http://redis.io/ (in-memory data structure store, used as database, cache and message broker) to save progress in the games.
First you want an unique index on the combination (userid, level) and then you want to do an update if the combination exists and an insert otherwise.
For how to create the unique index please take a look at How do I specify unique constraint for multiple columns in MySQL?
For how to code the SQL query to do update/insert please take a look at SQL: If Exists Update Else Insert
The article above uses Microsoft SQL syntax. In PHP you can code this by issuing the query and then using mysql_affected_rows to see how many rows where affected. If 0 rows where affected then you issue the INSERT query from PHP.
in pseudo code you need to do something like this in SQL.
UPDATE $table set column=value WHERE id=$ID
Hi brayan actually the problems is that no one will write code for you, you have to do it yourself. I guess you are unaware with SQL i.e., you asked that
how I configure this in the php script and mysql database to save the
information only once? because if the player with the id 50 play the
first level, will add a line with the information, but if the same
player play the first level again and change the amount of stars, I
dont want a new line, just update the stars amount.
Anyhow You first required some basic understanding of SQL and PHP with Unity. I will recommend you this Guide Server_Side_Highscores of unityWiki it help you to make database and server logic intergartion with PHP.
Now for your Second important part of question.
You have to update user code after each level completion.Or you can simply ask to user about socre save.
Before inserting new record into the database you have to check that userId with level id alread exist or not. some thing like this
Select userid, level, stars
from youTableName
where userid = ?
and level = ?
if the above query return empty response then you simply need to add the record
INSERT INTO table_name (userid, level, stars)
VALUES (value1,value2,value3);
Otherwise you have to update that specific column.

Multiple DB users updating at the same time

I am curious what path I should take to accomplish the following. I want multiple computers at one location to be able to view and make changes to data inside a mysql DB with a web browser. I dont have extensive knowledge in this area, but from what I do remember this was very difficult if not impossible.
Example: Lets say I have a record for John and I want 2 computers to be able to edit Johns record. Please note that the computers will not be editing the same portion of Johns record. Lets say one record is changing a status from need to be called to called and the other computer is changing the status of need to be ordered to ordered.
I want a solution that could natively handle this.
My current knowledge is building web interfaces with PHP and SQL. I would like to use these languages as I have some prior knowledge.
So my question: Is this possible? If, so exactly how would it work(flow of info)?
There are several ways that you can accomplish this. There's already some great PHP database editing software packages out there (phpMyAdmin).
To handle this in code though you can either use Transactions (depending on what flavor of SQL you're using this would be done differently)
One of the easier ways to ensure that you don't have people's data clashing with one another is just by adding additional where clauses to your statement.
Lets say you have a user record and you want to update the last name from Smith to Bill, and the user ID is 4.
Instead of writing
UPDATE users SET lastName='Bill' WHERE id='4'
You would add in:
UPDATE users SET lastName='Bill' WHERE id='4' AND lastName='Smith'
That way if someone else updates the last name field while you're working on it, your query will fail and you'll have to re-enter the data, thus faking a transaction
Use Transactions. Updating a single record at the exact same time isn't really supported, but applying one transaction followed immediately by another certainly is. This is native to MySQL.
START TRANSACTION;
SELECT #A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=#A WHERE type=1;
COMMIT;
One other thing to do is the old desktop approach. Wich is almost mannualy control the flow of modifications. I will show:
Say that you have a client table with the fields id, firstname, lastname, age. In order to control multiple users updates you will add the version integer default 0 field to this table.
When you populate the object on the form to an user you will also store the actual version that the user has selected.
So lets assume that your client table is like this:
id firstname lastname age version
1 Tomas Luv 20 0
2 Lucas Duh 22 0
3 Christian Bah 30 0
When the user select the client with the id=1 the version of this row is, in this moment, 0. Then the user update the lastname of this client to Bob and submit it.
Here comes the magic:
Create a trigger (before update) that will check the current version of that registry with the version that the user previously selected, something like this (this is just pseudo code, as I'm doing it from my head):
create trigger check_client_version on client before update as
begin
if new.version != old.version then
throw some error saying that a modification already was done;
else
new.version = old.version + 1;
end if;
end;
On the application you check if the update has this error and inform to user that someone else made change on the registry he try to change.
So with the given example it would be like:
1 - The user A selected the row 1 and start editing it
2 - At the same time the user B selected the row 1 and save it before the user A
3 - The user A try to save his modifications and get the error from the application
On this context the user A has the version field pointed to 0 also is the user B but when the user B save the registry it now is 1 and when the user A try to save it it will fail because of the check trigger.
The problem with this approch is that you will have to have a before update trigger to every table in your model or at least the one you are concerned with.

Save additional information to MYSQL Database and use a simple query, or use complex query?

I have a drupal site, and am trying to use php to grab some data from my database. What I need to do is to display, in a user's profile, how many times they were the first person to review a venue (exactly like Yelp's "First" tally). I'm looking at two options, and trying to decide which is the better way to approach it.
First Option: The first time a venue is reviewed, save the value of the reviewer's user ID into a table in the database. This table will be dedicated to storing the UID of the first user to review each venue. Then, use a simple query to display a count in the user's profile of the number of times their UID appears in this table.
Second Option: Use a set of several more complex queries to display the count in the user's profile, without storing any extra data in the database. This will rely on several queries which will have to do something along the lines of:
Find the ID for each review the user has created
Check the ID of the venue contained in each review
First review for each venue based on the venue ID stored in the review
Get the User ID of the author for the first review
Check which, if any, of these Author UIDs match the current user's UID
I'm assuming that this would involve creating an array of the IDs in step one, and then somehow executing each step for each item in the array. There would also be 3 or 4 different tables involved in the query.
I'm relatively new to writing SQL queries, so I'm wondering if it would be better to perform the set of potentially longer queries, or to take the small database hit and use a much much smaller count query instead. Is there any way to compare the advantages of either, or is it like comparing apples and oranges?
The volume of extra data stored will be negligible; the simplification to the processing will be significant. The data won't change (the first person to review a venue won't change), so there is a negligible update burden. Go with the extra data and simpler query.

Voting system questions

I'm having some trouble approaching a +1/-1 voting system in PHP, it should vaguely resemble the SO voting system. On average, it will get about ~100 to ~1,000 votes per item, and will be viewed by many.
I don't know whether I should use:
A database table dedicated for voting, which has the userid and their vote... store their vote as a boolean, then calculate the "sum" of the votes in MySQL.
A text field in the "item" table, containing the uids that already voted (in a serialized array), and also a numeric field that contains the total sum of the votes.
A numeric field in the "item" table, that contains the total sum of the votes, then store whether or not the user voted in a text field (with a serialized array of the poll id).
Something completely different (please post some more ideas!)
I'd probably go with option 3 that you've got listed above. By putting the total number of votes as another column in the item table you can get the total number of votes for an item without doing any more sql queries.
If you need to store which user voted on which item I'd probably create another table with the fields of item, user and vote. item would be the itemID, user would be the userID, vote would contain + or - depending on whether it's an up or down vote.
I'm guessing you'll only need to access this table when a user is logged in to show them which items they've voted on.
I recommend storing the individual votes in one table.
In another table store the summary information like question/poll ID, tally
Do one insert in to the individual votes table.
For the summary table you can do this:
$votedUpOrDown = ($voted = 1) ? 1 : -1;
$query = 'UPDATE summary SET tally = tally + '.$votedUpOrDown.' WHERE pollid = '.$pollId;
I'd go with a slight variant of the first option:
A database table dedicated for voting, which has the userid and their vote... store their vote as a boolean, then calculate the "sum" of the votes in MySQL.
Replace the boolean with an integer: +1 for an up-vote and -1 for a down-vote.
Then, instead of computing the sum over and over again, keep a running total somewhere; every time there is an up-vote, add one to the total and subtract one every time there is a down-vote. You could do this with an insert-trigger in the database or you could send an extra UPDATE thing SET vote_total = vote_total + this_vote to the database when adding new votes.
You'd probably want a unique constraint on the thing/userid pair in the vote tracking table too.
Keeping track of individual votes makes it easy to keep people from voting twice. Keeping a running total makes displaying the total quick and easy (and presumably this will be the most common operation).
Adding a simple sanity checker that you can run to ensure that the totals match the votes would be a nice addition as well.
serialized array: Please don't do that, such things make it very difficult to root around the database by hand to check and fix things, serialized data structures also make it very difficult (impossible in some cases) to properly constrain your data with foreign keys, check constraints, unique constraints, and what have you. Storing serialized data structures in the database is usually a bad idea unless the database doesn't need to know anything about the data other than how to give it back to you. Packing an array into a text column is a recipe for broken and inconsistent data in your database: broken code is easy to fix, broken data is often forever.

Categories