Use MySQLi Prepared Statement to Enter Dynamic, Multiple Rows into Database? - php

I have created a HTML form where users would submit their name, email, and language skills. Since a user may speak more than one language, user will be able to generate additional rows by clicking an "add" button.
The form will then be submitted and entered into a MySQL database. I'm using two tables to hold the received data, whereas the user-id in the first table will be auto_incremented:
| (user-id) | name | email|
| user-id | language | proficiency|
Now I'm trying to write the PHP code, which looks something like this:
$name = $_POST['name'];
$email = $_POST['email'];
$add_table1 = $mysqli->prepare("INSERT INTO table1 (name, email) VALUES (?, ?)");
$add_table2 = $mysqli->prepare("INSERT INTO table2 (user_id, language, proficiency) VALUES (?, ?, ?)");
$add_table1->bind_param("ss", $name, $email);
$add_table1->execute();
$user-id = $mysqli->insert_id;
foreach($_POST['language'] as $index => $language) {
$index = intval($index);
$language = mysql_real_escape_string($language);
$proficiency = mysql_real_escape_string($_POST['proficiency'][$index]);
$add_table2->bind_param("iss", $user-id, $language, $proficiency);
$add_table2->execute();
}
$add_table1->close();
$add_table2->close();
$mysqli->close();
The table should look like this
| 1 | Mark | mark#me.com |
| 2 | Sue | sue#me.net |
|1 | English | perfect |
|1 | Spanish | awesome |
|2 | English | great |
|2 | French | ok |
|2 | Korean | fluent |
However, with my code table 1 looks fine, but table 2 looks like this
| 1 | | |
| 2 | | |
Can somebody help? Thanks!

One thing I should point out is that you don't use mysql_real_escape_string with prepared statements.
Another thing is that $user-id is not a valid variable name. You can't use a hyphen.
Edit:
It's a good thing to turn on error reporting and to output mysqli/mysqli_stmt::$error when anything fails. Most problems can be resolved with these.

Your php mysqli code looks pretty good. Are you sure you are retreiving correctly the POST values? int the foreach loop print $language and $proficiency before executing the queries

Related

How to use LIKE statement to check if each value in an array is present in a SQL table? [duplicate]

I have the following example table and attributes:
---------------------------
| Name | Town |
---------------------------
| Name 1 | POOLE |
| Name 2 | POOLE/WALLASEY |
| Name 3 | POOLE/WALLASEY |
| Name 4 | POOLE |
---------------------------
I am using the following SQL statement in PHP to retrieve rows:
SELECT * FROM `table` WHERE `Town` LIKE '%".$global->getPlayerTown()."%'
Given the criteria POOLE the database returns:
---------------------------
| Name | Town |
---------------------------
| Name 1 | POOLE |
| Name 2 | POOLE/WALLASEY |
| Name 3 | POOLE/WALLASEY |
| Name 4 | POOLE |
---------------------------
However when using the criteria POOLE/WALLASEY the query returns:
---------------------------
| Name | Town |
---------------------------
| Name 2 | POOLE/WALLASEY |
| Name 3 | POOLE/WALLASEY |
---------------------------
How do I intelligently tell the PHP to split the string into separate criteria (i.e. POOLE and WALLASEY) in one query, so that the query retrieves all rows?
SELECT * FROM `table` WHERE `town` REGEXP 'POOLE|WALLASEY';
This will match any rows that has one or more instances of POOLE or WALLASEY.
As to the PHP side, depending on how many kinds of separators ('/' in this case) you have in your dataset, it can get rather messy rather quickly.
But replace '/' with '|' in getPlayerTown() would seem to be one way of doing it.
As to performance, I'm not sure how REGEXP is as opposed to LIKE.
https://dev.mysql.com/doc/refman/5.7/en/regexp.html
This is an iteration of an often-asked class of questions: How do I select on a single datum, if I have more than one in a field?
The answer, as always, is: You don't.
There are many reasons for that, but one of the most important is performance: Basically a LIKE '%...' can't use an index. That might be ok with a handful of test rows, but it quickly becomes a problem when scaling.
The only reliable ways are to
either normalize your data
or use a fulltext index
In your case I'd strongly vote for normalization: Create a towns table, then link it to the players via a join table. You can now search for any town with full index use, finding the players through the join.
As Marc B stated, using explode.
<?php
$array = explode("/",$global->getPlayerTown());
foreach($array as $Town){
$list = $list ."'%" .$Town ."%', ";
}
$SQL = "SELECT * FROM `table` WHERE `Town` LIKE ANY(" .$list .")";
?>
Please go the smart route and normalize your data. This idea may work, but that doesn't mean it is the best choice.
You could explode the towns, then loop through them and build the query like so:
$towns = explode('/', $global->getPlayerTown());
$first = true;
$like_sql = '';
foreach($towns as $town) {
$like_sql .= $first ? ' WHERE ' : ' OR ';
$like_sql .= "`Town` LIKE '%{$town}%'";
$first = false;
}
$query = "SELECT * FROM `table` {$like_sql}";
However I would recommend you normalise your data, and have a separate towns table, with a user_town pivot table.

choose rows where 10 columns

I want to get a rows using one string, but this string is used to validate more than 1 column, exactly 5, for example
-----------------------------------------------
| id | code | 1 | 2 | 3 | 4 | 5 |
-----------------------------------------------
| 01 | Number | 5 | 7 | 10 | 21 | 1 |
| 02 | String | v | q | s | f | w |
| | | | | | | |
| | | | | | | |
| | | | | | | |
-----------------------------------------------
I want to make SELECT mysqli where using 5 columns ( 1, 2, 3, 4, 5 ) if i use looping method, it will waste a lot of time
i have tried the problem with this code
$value = "q";
for ($x = 1; $x <= 5; $x++) {
$cek = mysqli_query($con,"SELECT * FROM table where $x='$value' and id='02'")
if(mysqli_num_rows($cek) == 1) {
echo "success";
} else {
echo "fail";
}
}
I use this code successfully, but the process is too long
is there an easier and more practical way to overcome this problem? thank you
As has been pointed out in comments, your database design is sub-optimal. You may want to reconsider and change it. Also, having column names be 1, 2, etc. is a very bad idea. At least have them start with a letter. Better yet, give them some reasonable names indicating what data those columns actually contain.
Now, assuming you figured out what your column names should really be, you can use a simple IN operator to get your data. The usual/common way of using it is
WHERE some_column IN ('value1', 'value2', ...)
Yet, there's nothing preventing you from using it the other way around:
WHERE 'some_value' IN (column1, column2, ...)
This way, your SQL statement becomes something like this:
SELECT *
FROM table
WHERE '$value' IN (column1, column2, column3, column4, column5)
AND id='02'
Now, if you have your column names in an array, you can do it this way:
$testColumns = ['column1', 'column2', 'column3', 'column4', 'column5'];
$value = "q";
$inColumns = implode(',', $testColumns);
$sql = "SELECT * FROM table WHERE '$value' IN ($inColumns) AND id='02'";
$cek = mysqli_query($con, $sql);
UPDATE: If your column names are non-standard, e.g. the aforementioned 1, 2, etc., or have spaces in them, then simple implode will not work, because you need to back-quote each column name. In that case, you would need something like this:
$inColumns = implode(',', array_map(function($c) { return "`$c`"; }, $columns));

return '-' dash if value doesn't exist in two tables in mySQL and PHP

I'm quite new with databases and stuck with this situation.
My databases data updates from another URL. The local database is updated once per week, so I can't be sure when the data changes or does all of the data exist in all of the tables.
That's why I need to compare Spec_Names and if the Spec_Name doesn't exist i.e. table_2, the program should print a dash as an indicator for the user.
table_1
+----------+-----------+--------------+
| category | Spec_Name | Spec_Value |
+----------+-----------+--------------+
| Engine | x | 111111111111 |
+----------+-----------+--------------+
| Engine | y | 222222222222 |
+----------+-----------+--------------+
table_2
+----------+-----------+--------------+
| category | Spec_Name | Spec_Value |
+----------+-----------+--------------+
| Engine | x | 111111111111 |
+----------+-----------+--------------+
So, the Spec_Name.y wouldn't exist in table_2.
In that case, I'd like to show this for a user:
+---------+----------------+----------------+
|Spec_Name| car1.Spec_Value|car2.Spec_Value |
+---------+----------------+----------------+
| x | 111111111111 | - |
| y | - | 55555565 |
| z | 333333333333 | 77777777 |
etc.
Currently I loop throught my data with PHP loops like this one:
function printCarData($conn, $table){
$query = "SELECT Spec_Name, Spec_Value, SUBSTRING(Spec_Value, 1, 20), TechSpecCategoryName FROM ".$table;
if($result = mysqli_query($conn, $query)){
echo"<ul>";
while($row = mysqli_fetch_assoc($result)){
if($query != $row["TechSpecCategoryName"]){
echo "<li>"."<br>"."</li>";
}
echo "<li>".$row["SUBSTRING(Spec_Value, 1, 20)"]."</li>";
$query = $row["TechSpecCategoryName"];
}
echo"</ul>";
}
}
printCarData($link, $table_name)
I thought to use COALESCE(), but I could not figure out, how to use it in situations as this is.
Also, I thought I could achieve this with PHP, but there are 144 Spec_Names in perfect cases, so it would be a quite long, hacky and expensive function.
Thirdly I thought, is there a way to use template tables in MySQL. So, I would have a table with all possible Spec_Names
It would be great, if anybody could point me the right direction.

Bulk insert from multiple data sources using PDO

I am trying to insert rows into a MySQL table using PHP/PDO, from two sources, namely :
Another Table (Same database)
PHP
The table I am filling looks like this :
Table Name : data_sink
+-------+-----------+--------------+-----------+
| ID | data1 | data2 | data3 |
+-------+-----------+--------------+-----------+
| 1 | text_1 | aa | 8 |
| 2 | text_2 | bb | 8 |
| 3 | text_3 | cc | 8 |
| 4 | text_4 | dd | 8 |
| 5 | text_5 | ee | 8 |
| 6 | text_6 | ff | 8 |
+-------+-----------+--------------+-----------+
In this, data1 and data2 are taken from another table, however data3 comes from the PHP code. I used the following query to get data from just the table :
$insert_rows = $db->prepare("INSERT INTO data_sink (data1, data2)
SELECT username, usergroup FROM data_origins WHERE <condition>");
I am unsure of how to add data3 into this query. I have found a workaround for this by adding another column to my origin table, and filling all rows with the value "replaceme", and then running the query as follows :
$insert_rows = $db->prepare("INSERT INTO data_sink (data1, data2, data3)
SELECT username, usergroup, temp_value FROM data_origins WHERE <condition>");
I then run an additional query, updating the table wherever data3 is set to "replaceme"
$update_rows = $db->prepare("UPDATE data_sink SET data3 = :data3
WHERE data3 = 'replaceme'");
Is there a single step method of solving this problem, to combine inputs from MySQL and PHP? [NOTE : For every batch of inserts, all rows share a common value for data3]
Could be as simple as
$insert_rows = $db->prepare("INSERT INTO data_sink (data1, data2, data3)
SELECT username, usergroup, ? FROM data_origins WHERE <condition>");
$insert_rows->bindParam(1, $data3);
$insert_rows->execute();
This of course assumes that your $data3 is the same for all rows that are being inserted. It's also possible to do a simple arithmatic operation or function call to ensure that each row gets a different value based on $data3

MYSQL Update and add a value into cell

hello friends I want to update a cell in a table whit new content, but retaining the content that has. I need to add the new data separated whit comma or line break (is'nt relevant), preserving the data that have inside.
|id | title | referer|
|--------------------|
| 1 | post1 | google |
| 2 | post2 | yahoo |
| 3 | post3 | bing |
| 4 | post4 | google |
The table should look like this with new content added.
|id | title | referer |
|-------------------------------|
| 1 | post1 | google,yahoo,bing |
| 2 | post2 | yahoo,bing,etc |
| 3 | post3 | bing |
| 4 | post4 | google,google |
this is my code to insert new rows in my Database:
mysql_query("INSERT IGNORE INTO posts (id,title,referer) VALUES (null,'$q','$referer')");
What would be the code to add information in the cell "referer" whit Comma separated or line break ?
thanks in advance
I am not sure about what you might do with how separate them with commas unless you will want to create an array of variables and concat them into a single variable and use mysql's CONCAT function to update your table in order to keep your last field data:
$referes_list = '';
foreach ($referers as $referer) {
$referes_list .= $referer . ", ";
}
UPDATE referers SET referer=CONCAT(referer,'$referes_list') WHERE id='$id' ;
You'll have to forgive me if my MySQL skills aren't the greatest, but what I would do here is simply get the current value, append a comma and new value to it, then update the cell.
...Or did I misinterpret your question?
In mysql there isnt "comma separated type", that is just a simple string or VARCHAR, so, you will need get previous data and concatenate it like string in php and then update it.
I think you are looking for something like:
update t
set referrer = (case when referer is null or referer = ''
then #newvalue
else concat(referer, ',', #newvalue)
end)
where id = #id;
mysql_query('UPDATE tablename SET referer = concat(referer,", '.$value.'") where id="'.$id.'")';
this should do it, it's untested though.

Categories