PHP contest Logical - php

In one of my web application in php there is a contest section . It contains a multiple choice 10 questions , Each has 4 options .
After user filling the form I am saving the answer as comma separated values in a db . like follows:
user | answer
-------------------------------------
112 | 1,7,8,9,8,5,2,3,6,7,9,6
I got a answer key same as the use's filled answer key ..
What is the best logical method for evaluate the users input and find out the highest scored user?

As mentioned in the comments, this isn't the best way to store data, but I'd evaluate like this:
$query = mysql_query("select * from `table` where 1",CONNECTION_IDENTIFIER) or die("die message");
$answer_key = array(answer1,answer2,etc);
$high_score = 0;
$high_scorer= "";
while($r=mysql_fetch_array($query)){
$users_answers = explode(',',$r['answer']);
$user_score = 0;
for($i=0;$i<10;$i++){
if ($answer_key[$i]==$users_answers[$i]){
$user_score++;
}
}
if ($user_score > $high_score){
$high_score = $user_score;
$high_scorer = $r['user'];
}
}
echo "High scorer is $high_scorer with $high_score points";

if you have answers with scores like that:
$answersRating = array(1 => 0, 2=> 1, 3 => 3, 4 => 2, ....) when selecting answer 1 he got 0 points, for 2 => one point, for 3 => 3 points and so on. You can do something like that:
$score = array_sum(array_intersect_key($answersRating, array_flip(explode(',', $userAnswersStringFromDB))));

I think you should structure your DB like this:
NOTE: This is bare minimum, you of course would add extra fields to questions like name, description, etc
answers | id, user_id, question_id, answer
questions | id, contest_id, correct_answer
user | id, name
Then you could get everything with a query.
Top Score:
SELECT u.name,count(*) as Score FROM user u, answers a, questions q WHERE u.id=a.user_id and q.id = a.question_id and q.correct_answer=a.answer WHERE q.contest_id=XXX ORDER BY Score

Related

MYSQL PHP: Find duplicates based on Address Column

I have an addresses table in my MYSQL database with the following structure:
The first column ID, is a primary, auto-increment column.
The second column Name is varchar.
The third column contains address (text), filled by user.
The forth column contains address slug, which is basically the address (Third Column) in lower case and without any special characters.
The last column contains the creation date of the record.
I wish to display all the records and highlight the possible duplicates, based on the address/address slug.
In this case, the duplicates are as follows:
Record 1 and Record 2
Record 3 and Record 6
Is there a way to partially match a string in MYSQL or PHP, to achieve the above results?
FYI: I have gone through SPHINX PHP, SQL FULLTEXT SEARCHES etc.
I have been struggling over 2 weeks, but couldn't find any optimal solution.
Any ideas, suggestions, solutions are welcome.
Since laravel was tagged initially, later removed, I thought the strategy can still help.
This is the given list:
$lists = [
[
'id' => 1,
'text' => '2693 Edgewood Road Exit',
],
[
'id' => 2,
'text' => '4408 Cost 4657 Avenue',
],
[
'id' => 3,
'text' => '2693 Mapleview Road',
],
[
'id' => 4,
'text' => '4657 Cost Edgewood Avenue',
],
[
'id' => 5,
'text' => '4408 Mapleview Drive Road',
]
];
Goal is to find repetitive/duplicate texts from each.
Since finding duplication of ONE word is not a real scenario, I thought of finding the duplication with TWO words with all the combinations possible.
$combinations = [];
foreach ($lists as $list) {
$insideCombo = [];
$insideText = explode(' ', $list['text']);
$length = count($insideText);
for ($i = 0; $i < $length; $i++) {
for ($j = $i + 1; $j < $length; $j++) {
if (isset($insideText[$j])) {
$insideCombo[] = $insideText[$i] . ' ' . $insideText[$j];
}
}
}
$combinations[$list['id']] = $insideCombo;
}
This is gonna return
// for '2693 Edgewood Road Exit'
1 => array:6 [
0 => "2693 Edgewood"
1 => "2693 Road"
2 => "2693 Exit"
3 => "Edgewood Road"
4 => "Edgewood Exit"
5 => "Road Exit"
]
Now, we loop again to compare the possible repetition. Here, we leverage Laravel's Str::containsAll()
$copyCat = [];
foreach ($lists as $list) {
foreach ($combinations as $comboKey => $combination) {
/* no need to compare the text with itself &&
* to avoid duplication of '4 to 2' if '2 to 4' is already mentioned
*/
if ($list['id'] != $comboKey && $list['id'] < $comboKey) {
foreach ($combination as $row) {
if (Str::containsAll($list['text'], explode(' ', $row))) {
$copyCat[] = $list['id'] . ' matches with ' . $comboKey . ' with "' . $row . '"';
}
}
}
}
}
Final Response of $copyCat
array:5 [
0 => "1 matches with 3 with [2693 Road]"
1 => "2 matches with 4 with [4657 Cost]"
2 => "2 matches with 4 with [4657 Avenue]"
3 => "2 matches with 4 with [Cost Avenue]"
4 => "3 matches with 5 with [Mapleview Road]"
]
Keep me posted in the comments below. Cheers!
Make an empty duplicate of the table - e.g. mytable_to_update.
Run a few queries to find out duplicates.
Start with populating the newly created table with non-duplicates. Initial query:
SELECT SUBSTRING_INDEX(Name,' ',1),COUNT(*)
FROM mytable_to_update
GROUP BY SUBSTRING_INDEX(Name,' ',1) HAVING COUNT(*) = 1;
The SUBSTRING_INDEX will capture the first string before space (' '). In the example, Sam Mcarthy will become Sam only. Then using that to group and count how many name occurrences it has. HAVING COUNT(*) = 1 will only show any name occurring once. But that might as well return nothing if there's a name like Joe and Joe John but the two are actually a different person with different addresses (since the first query only group by the first name occurring). Therefore, we need to add address comparison in the mix.
Add the same function to the Address column like this:
SELECT SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1), /*we take the first string in the address*/
COUNT(*)
FROM mytable_to_update
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1) /*then add group by for the address*/
HAVING COUNT(*) = 1;
Similarly, we take only the first string occurrence from the address. So let's say for example there are two data that looks like this, Joe, 12 Street.. and Joe John, 12 St. .., what will happen is the query above will (given the SUBSTRING_INDEX function) take only the first string occurrence; Joe, 12 , which will return the count value as 2. That means both data (Joe, 12 Street.. and Joe John, 12 St. ..) are considered as duplicates and will not show in the query results.
Change the query to list out all non-duplicates ID to be inserted into mytable_to_update table:
INSERT INTO mytable_to_update
SELECT * FROM mytable WHERE ID IN
(SELECT GROUP_CONCAT(ID) /*replace everything else in the select with just `ID`*/
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) = 1) ;
Note: I'm using GROUP_CONCAT(ID) because of incompatibility of sql_mode=only_full_group_by - if it's being set. Of course the result could be different (like '1,2' or '1,,,,,') but since we're only looking at any count=1, it shouldn't have a problem as it will only return 1 value. I've tested with ANY_VALUE it also return similar results.
Now you have all the non-duplicates inside the mytable_to_update table. the next step is to search for duplicates and insert the ones that you only want. This is merely a suggestion/assumption of what you might want and it's not 100% accurate due to the nature of the data value that we're comparing.
The query is similarly structured and changed only in a few places, for example:
SELECT GROUP_CONCAT(ID), /*add GROUP_CONCAT to list all the duplicates group by the first name & address string.*/
Name,
Address,
COUNT(*)
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1; /*Change '= 1' to '> 1' to get any records with more than 1 count.*/
Using GROUP_CONCAT to generate a comma separated list of ID that has possible duplicates.
Then add GROUP_CONCAT over all the columns listed with identical ORDER BY so every columns will be ordering by the same thing.
SELECT GROUP_CONCAT(ID ORDER BY ID), /*add ORDER BY*/
GROUP_CONCAT(Name ORDER BY ID),
GROUP_CONCAT(Address ORDER BY ID),
COUNT(*)
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1;
With this you go over the values it returned for any of the duplicates and compare it side by side. That way you can decide to omit any ID that you don't want to appear in the list by adding WHERE ID NOT IN(1,3 ...) etc.
Once you've finalized which ID you want to keep, you can do something like this:
INSERT INTO mytable_to_update
SELECT * FROM mytable WHERE ID IN
(SELECT SUBSTRING_INDEX(GROUP_CONCAT(ID ORDER BY ID),',',1)
/*assuming that you only want the first ID in the set, do SUBSTRING_INDEX to separate the first ID*/
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1);
Now you'll have a table (mytable_to_update) that might probably have all non-duplicates. In case some of the data in the mytable_to_update are not what you want, you can just remove it or in case there are some data you think is not a duplicate, you can insert it. It's pretty much a manual process afterwards; well, even with the queries, only yourself can determine whether the processes/data are correct.
Here's a fiddle: https://www.db-fiddle.com/f/6Dfrn78mqZbGTwZs3U9Vhi/0

MYSQL / PHP Calculating number of occurrences

First off all I am slightly confused what the best implemtentation would be for the following problem i.e pure can it be done with only mysql without altering tables or would I need a combination of PHP and mysql as I am currently doing.
Please keep that in mind as you read on:
Question Info
A Pickem game works as follow:
1- Display all matches / fixtures in a round for a tournament.
2- User enters which teams he thinks will win each fixture.
The fixtures are pulled from a table schedule and the users results are recorded in a table picks
Keep In mind
Each round can have a number of matches (anywhere between 1 to 30+ matches)
What I am trying todo / PROBLEM
I am trying to calculate how many users selected team1 to win and how many users selected team2 to win for a given round in a tournament.
Example
Manchester United: 7 users picked |
Arsenal 3: users picked
MYSQL TABLES
schedule table Schedule of upcoming games
picks table User Picks are recorded in this table
Expected Output From Above Tables After Calculations
So for Super Rugby Round 1 it should read as follow:
gameID 1 4 picks recorded, 2 users selected Jaquares 1 user Selected Stormers (ignore draw fro now)
gameID 2 4 picks recorded, 4 users selected Sharks, 0 users selected Lions
My Code
function calcStats($tournament, $week)
{
global $db;
//GET ALL GAMES IN TOURNAMENT ROUND
$sql = 'SELECT * FROMpicks
WHERE picks.tournament = :tournament AND picks.weekNum = :weekNum ORDER BY gameID';
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':tournament', $tournament);
$stmnt->bindValue(':weekNum', $week);
$stmnt->execute();
if ($stmnt->rowCount() > 0) {
$picks = $stmnt->fetchAll();
return $picks;
}
return false;
}
test.php
$picks = calcStats('Super Rugby', '1');
foreach($picks as $index=> $pick) {
if($pick['gameID'] !== $newGameID){
?>
<h1><?php echo $pick['gameID']?></h1>
<?php
//reset counter on new match
$team1 = 0;
$team2 = 0;
}
if($pick['picked'] === $newPick){
//gameID is passed as arrayKey to map array index to game ID
//team name
$team1[$pick['picked']];
//number times selected
$team1Selections[$pick['gameID']] = $team1++;
}
else if($pick['picked'] !== $newPick){
///gameID is passed as arrayKey to map array index to game ID
//team name
$team2[$pick['picked']];
$team2Selections[$pick['gameID']] = $team2++;
}
$newPick = $pick['picked'];
$newGameID = $pick['gameID'];
}
PRINT_R() Of function $picks = calcStats('Super Rugby', '1')
I hoe my question makes sense, if you need any additional information please comment below, thank you for taking the time to read.
It seems that you're doing too much within PHP that can be easily done within MySQL; consider the following query:
SELECT gameID, team, COUNT(*) AS number_of_picks
FROM picks
WHERE picks.tournament = :tournament AND picks.weekNum = :weekNum
GROUP BY gameID, team
ORDER BY gameID, team
This will give the following results, given your example:
1 | Jaquares | 2
1 | Stormers | 1
1 | Draw | 1
2 | Sharks | 4
Then, within PHP, you perform grouping on the game:
$result = array();
foreach ($stmnt->fetchAll() as $row) {
$result[$row['gameID']][] = $row;
}
return $result;
Your array will then contain something like:
[
'1' => [
[
'gameID' => 1,
'team' => 'Jaquares',
'number_of_picks' => 2,
],
'gameID' => 1,
'team' => 'Stormers',
'number_of_picks' => 1,
],
...

delete item the order changes php

I have a page that has a column "order". When I add a new item the order should be 1 + max of the item. But if I delete an item between these values like i have 8 9 10 , if I delete item with 9 the new item will have 11 value and I will have 8 10 11.But I want 8 9 10. How can I do this in php? should I create a function? It works to add a new item with the max+1, but if I delete is not good.
My code:
$queryMaxOrd = mysql_query("select max(ord) from article where user_id=" .$_SESSION['userId']);
$row = mysql_fetch_row($queryMaxOrd);
$valueMaxOrd = $row[0] + 1;
$_SESSION['a'] = $valueMaxOrd;
and the insert query....
Any ideas?
First thing to consider is removing mysql_* and start using mysqli_* or pdo. Your code is vulnerable to sql injections.
With your code structure you have you adding each order as a new record to your table, so when you have 5 orders with one users your table will look like this.
user: Adiiia | order: 5
user: Adiiia | order: 3
user: Adiiia | order: 7
user: Adiiia | order: 2
user: Adiiia | order: 9
when you query the database you are saying to mysql: get me the maximum number of the record i have with user: Adiiia. The result should be 9
If you want to count the sum of the records you should use sum
select sum(ord) from article where user_id='".$_SESSION['userId']."'
The result should be 26
The best thing you can do is by creating a new table orders_sum
The structure should like like this.
Total_orders | User
when a user have a new order you can update the table by adding one or else if have a order removed then removing minus one order.
Something like this.
Total_orders | User
5 | Adiiia
When you want to update:
select Total_orders from orders_sum where User='Adiiia'
Find how many orders the user have by fetching the table.
$orders = $row['Total_orders'];
$plus_orders = $row['Total_orders'] + 1;
update orders_sum set Total_orders='".$plus_orders."' where user='Adiiia'
When you want to delete:
select Total_orders from orders_sum where User='Adiiia'
Find how many orders the user have by fetching the table.
$orders = $row['Total_orders'];
$minus_orders = $row['Total_orders'] - 1;
update orders_sum set Total_orders='".$minus_orders."' where user='Adiiia'
Lets say article table having primary key article_id then after delete any article for user_id. Fetch all the article_id for the user_id. Then update the order for all the article_id for that user.
$queryArticle = mysql_query("select article_id from article where user_id=" .$_SESSION['userId']." order by article_id asc");
$allArticle = [];
while($rowArticle = mysql_fetch_assoc($queryArticle)){
$allArticle[] = $rowArticle['article_id'];
}
$query = "UPDATE article SET ord = (CASE order ";
foreach($allArticle as $order => $article_id) {
$query .= " WHEN {$article_id} THEN {$order}";
}
$query .= " END CASE) WHERE article_id IN (" . implode(",", $allArticle) . ")";

How can I insert into a table only when certain field values are not the same?

So, for sake of simplicity, let's say I've got a table like this (f1,f2,f3 are fields):
f1 f2 f3
a b c
d e f
And say I've got a PHP array like this I want to add in to the table:
a g h
Now, I want to be able to add this one in, but I don't want to be able to add something like this:
a e f
Field f1 can have duplicates. Fields f2 & f3 cannot. I've tried adding a unique index to f2, and used REPLACE INTO, but it's not what I want. I need there to be a way to only insert if the f2 & f3 field entries are not already found on the same row in the database table.
$query = "REPLACE INTO table1 (title, description, start, end, location, affiliation)
VALUES ('{$my_title_php_array[$count]}',
'{$my_description_php_array[$count]}',
'{$my_start_php_array[$count]}',
'{$my_end_php_array[$count]}',
'{$my_location_php_array[$count]}',
'{$my_affiliation_php_array[$count]}')”;
description is of data type 'TEXT', which can't be used as an INDEX (too big). Ideally, I'd like to have all be necessarily checked in comparison with the incoming PHP array entries.
Let's say I have these things in my new example's PHP array:
Title1 Desc1 1:00pm 2:00pm Loc1 Aff1
Title1 Desc1 3:00pm 4:00pm Loc1 Aff1
Title2 Desc2 1:00pm 2:00pm Loc2 Aff2
Title2 Desc1 1:00pm 2:00pm Loc3 Aff3
These should all be considered unique and entered in. I'd like to be able to enter them only when they don't exactly match a row in my database already. Desc1 is long. The descriptions are usually the most unique. Is there a way of shortening?
I had to look up this information myself recently and here is the answer I found:
Use multiple columns as unique identifier for mysql
I believe it's what you're needing.
Globally, you want a constraint on a pair of entry? In MySQL, I think you can't. Just, do a select (something like SELECT COUNT(*) FROM _table WHERE f1 = ? AND f2 = ? replace with your values) check the result.
I personally would use PHP and mysql to check the database table for existing rows for "f2" and "f3".
For sake of simplicity, I will use standard mysql and will assume the table name is "alphabet". Example:
$array = array('a', 'e', 'f');
$checkTable = mysql_query("SELECT * FROM `alphabet` WHERE `f2` = '".$array[1]."' OR `f3` = '".$array[2]."'");
if(!mysql_num_rows($checkTable)){
mysql_query("INSERT INTO `alphabet` VALUES('".$array[0]."', '".$array[1]."', '".$array[2]."')");
}
Something like the above. Lets go through it together.
We first set the array containing the letters "a", "e", and "f".
$array[0] = "a", $array[1] = "e", and $array[2] = "f".
We check in the database for any rows where the field "f2" or "f3" is equal to the second and third parameter of our array.
Using mysql_num_rows() if there is no duplicates it will go ahead and add the array into the database table "alphabet".
Correct me if I am wrong or if anybody has a simpler solution. Hope I helped.
<?php
$data[] = 'f1 value';
$data[] = 'f2 value';
$data[] = 'f3 value';
for ($i = 0; $i < count($data); $i++) {
for ($j = $i+1; $j < count($data); $j++) {
$value_a = $data[$i];
$value_b = $data[$j];
$query = "SELECT *FROM mytable WHERE ";
$query.= "(f1=".$value_a." AND f2=".$value_b.") OR";
$query.= "(f1=".$value_a." AND f3=".$value_b.") OR";
$query.= "(f2=".$value_a." AND f3=".$value_b.")";
$result = mysql_query($query);
if (mysql_num_rows($result)) {
//duplicated
}
}
}
?>

simple php mysql search engine with checkboxes

I would like to do a search engine for my webpage.
I have several tables in my mysql database and i would like them
combined when user
Table users
id name age country vip profile_image
1 nick 23 sweden 1 yes
2 michael 20 germany 0 no
3 laura 19 usa 1 yes
4 gary 33 china 1 yes
Table online
id user_id online
1 1 1
2 2 1
3 4 1
user_id is connected to id in users table
Now i have checkboxes
[ ] Those which are online
[ ] Those which are vip
[ ] Those with profile image
Im coding my page in PHP and im trying to figure how to include certain
searches in a sql query if certain checkbox is checked.
I can have tons of options here. Example if no checkbox is checked,
iff on you want to search for those which are online, how do i go in to the second table?
I hope you get my point here. I really hope someone could help me
and give me an working example of the php & sql query.
Cheerz!
First you have to check which checkboxes have been checked. Then you must write MySQL-query with PHP based on that information. You must think in every checkbox, what information it needs to check. If your database is well written, there is seldom a problem that two options affect each other. If information is in users-table, you need just write line to where-clause. If you need to join table to users-table to get information you need to do that too. Here is an example
$query = "";
$query .= "SELECT users.* FROM users";
if ($include_online == 1) {
$query .= " LEFT JOIN online ON online.user_id = users.id";
}
$query .= " WHERE";
if ($include_vip == 1) {
$query .= " users.vip = 1 AND";
}
if ($include_image == 1) {
$query .= " users.profile_image = 'yes' AND";
}
if ($include_online == 1) {
$query .= " online.online = 1 AND";
}
$query .= " users.name LIKE '%".$search_string."%'";
You need to form a query something like the following:
SELECT users.name, users.age, users.country
FROM users
LEFT JOIN online ON user.id = online.user_id
WHERE ((user.vip = 1) && (online.online = 1))

Categories