Inserting a multidimensional array into a MySQL Table text field - php

I'd like to insert a multidimensional array into a MySQL Database field so that it can then easily be read from the database at a later date back into an array. What's the best way to achieve this?
I've tried the following to no avail:
$id = "MXB-487"
$items = Array(Array("Coffee", "Blend", "500"), Array("Coffee1", "Blend1", "250"));
$items = implode(",", $items);
mysqli_query($con,"INSERT INTO carts (id, items)
VALUES ($id, $items)");
/*Code that pulls the array from the Database based on id and stores in variable $info*/
restored_mdarray = explode(",", $info);

ID in MySql, is usually unique (I'm pretty sure you specified it that way). So, you can't share the ID for multiple items. Also, imploding will end up with the following query:
INSERT INTO carts (id, items) VALUES(MXB-487, Array, Array)
Because you have a multidimensional array you're trying to implode, it doesn't recursively implode.
What you should do is loop through the objects, and I'm not sure how the relationship here works, but it looks like you need a relation table to connect those items. Consider the following structure:
Carts:
+----------+-----------+
| ID | Name |
+----------+-----------+
--<-| MXB-487 | Blah blah |
| +----------+-----------+
|
| Items:
| +----------+-----------+----------+-----------+
| | Cart_ID | Type1 | Type 2 | Amount |
| +----------+-----------+----------+-----------+
--->| MXB-487 | Coffee | Blend | 500 |
+----------+-----------+----------+-----------+
And in order to implement that in PHP, you'd do something like this:
<?php
$id = "MXB-487";
$items = array(
array("Coffee", "Blend", "500"),
array("Coffee1", "Blend1", "500"),
);
$sql = "INSERT INTO actions (cart_id, type1, type2, amount) VALUES ";
$items_sql = array();
if (count($items)) {
foreach ($items as $item) {
$items_sql[] = "('$id', '{$item[0]}', '{$item[1]}', '{$item[2]}')";
}
}
$sql .= implode(", ", $items_sql);
And then run the query.
It will look like this:
INSERT INTO actions (cart_id, type1, type2, amount) VALUES ('MXB-487', 'Coffee', 'Blend', '500'), ('MXB-487', 'Coffee1', 'Blend1', '500')
Which you can later select as such:
<?php
$id = "MXB-487";
$sql = "SELECT * FROM actions WHERE (cart_id = '$id')";
Though as a side note, I suggest you look at PDO and how to bind values, or at least learn to escape your values in the SQL to prevent future injections.
I speculated the structure of the tables, of course you can modify to your needs.
To connect the tables properly via SQL (to fasten the fetching later on) you can use FOREIGN KEY when you define the table:
CREATE TABLE actions (
id INT(11) NOT NULL AUTO_INCREMENT,
cart_id VARCHAR(32) NOT NULL,
type1 VARCHAR(32) NOT NULL,
type2 VARCHAR(32) NOT NULL,
amount INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (cart_id) REFERENCES carts(id)
)

Use serialize:
$a = array(array(1,2,3), array(3,4,5));
$b = serialize($a);
# write $b to and later read $b from database
$c = unserialize($b);
$a == $c # => true

Related

On duplicate key update for multiple values that aren't the primary key

I need to basically do an "insert if not exists else update" type query, and the way everything I've read tells me to go is Insert into...On Duplicate Key Update. The thing is, my primary key is an autoincrement value that I never interact with or keep track of and I can't really dynamically generate it to put into my query.
A typical row would be:
ID| Project_ID | Location | Cost_Center_Category | Name | Number | Year | Q_1 |
1 | 200 | NUH | 1 |asfoi | 1098123|etc.
Basically the uniqueness (not literally) of each row came with the combination of Project_ID, Location, Cost_Center_Category, Name, Number, and year. If those all were identical, then an update to Q_1 would occur.
UPDATE Labour_Planning
SET $Q = $submit
WHERE Project_ID = $selected_project
AND Year = $selected_year
AND Cost_Center_Category = $CCC
AND Cost_Center_Name = '$CC'
AND Cost_Center_Number = '$CC_Number'
AND Location = '$location';
Yeah, I know, SQL injection and all that, I will make this better. For now, I need to figure out a way to basically insert a row if ANY of the above columns are different. Is that possible with the Insert into....On Duplicate key?
Every example I see uses the primary key in their insert statement, and that's not really possible in this case.
I have done some test and thats what I get
create table test.a (
a int PRIMARY KEY,
b int,
c int
);
create UNIQUE index some_index on test.a(b,c);
insert into test.a VALUES (1,2,3);
insert into test.a VALUES (2,2,3); -- fails
insert into test.a VALUES (2,2,3) ON DUPLICATE KEY UPDATE a = 2; -- updates
Thus, all you need is to create composite unique index on fields that you consider must be unique.
I didn't want to do this for fear of obnoxious overhead, but considering I won't actually have many updates/inserts at a time, I just went with this.
$labour_select = "SELECT Project_ID
FROM Labour_Planning
WHERE Project_ID = $selected_project
AND Year = $selected_year
AND Cost_Center_Category = $CCC
AND Cost_Center_Name = '$CC'
AND Cost_Center_Number = '$CC_Number'
AND Location = '$location';";
$result = $mysqli->query($labour_select);
$num_rows = mysqli_num_rows($result);
if ($num_rows == 0){
$labour_insert = "INSERT INTO Labour_Planning (Project_ID, Location, Cost_Center_Category, Cost_Center_Name, Cost_Center_Number, Year, $Q) VALUES ($selected_project, '$location', $CCC, '$CC', '$CC_Number', $selected_year, $submit)";
$insert_result = $mysqli->query($labour_insert);
}
else {
$labour_update = "UPDATE Labour_Planning
SET $Q = $submit
WHERE Project_ID = $selected_project
AND Year = $selected_year
AND Cost_Center_Category = $CCC
AND Cost_Center_Name = '$CC'
AND Cost_Center_Number = '$CC_Number'
AND Location = '$location';";
$update_result = $mysqli->query($labour_update);
}
Now to look up prepared statements! I hear not only do they keep you protected from sql injection, it will make things of this nature faster as well! Thanks for all the help!

SQL - Inserting data where values are an array

I want to be able to add an array of strings to a table so that each string is a new row (in PHP).
This is it in psuedo-code:
$Array = "10000,10001,10002,10003";
$Data = "ImportantData";
mysqli_query($db, "INSERT INTO MyTable(`id`,`data`) VALUES($Array, $Data)");
So that a previously empty table would look like:
id | data
------------------------
10000 | ImportantData
10001 | ImportantData
10002 | ImportantData
10003 | ImportantData
In an update script, with those rows already established, I could just say:
mysqli_query($db, "UPDATE MyTable SET data = $Data WHERE `id` IN($Array));
However I want it to create rows, not just update old ones.
Is there any way I can do this?
Just create a foreach loop on $Array, and insert the data. I assume you want to update it if it exists as it makes little sense to create a new record with the same PK, so use the following (assumes you are using PHP PDO
INSERT INTO MyTable (id,data) VALUES (:id,:data) ON DUPLICATE KEY UPDATE data=:data;
Use REPLACE INTO:
REPLACE INTO table SET id = 10001, data = 'new important data';
MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/replace.html

Using Joins to Eliminate Multiple SELECTs in Loop

I'm trying to teach myself PHP/mysql by building a joe's goals clone, if you will.
Basically each user has multiple goals, and each day they record how many times a certain event occurred. For example, say my goal is to drink only 1 cup of coffee per day. If I had 3 today (oops!), I'd record 3 "checks" for today. I use a table called 'checks' to hold the check count for each day.
I have the following tables, and sample inserts:
CREATE TABLE `users` (
`user_id` int(5) NOT NULL AUTO_INCREMENT,
`user_email` varchar(50) NOT NULL,
`user_name` varchar(25) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
-- Dumping data for table `users`
INSERT INTO `users` VALUES (1, 'xxx#xxx.com', 'xxx');
INSERT INTO `users` VALUES (2, 'some#guy.com', 'SomeGuy');
CREATE TABLE `goal_settings` (
`goal_id` int(5) NOT NULL AUTO_INCREMENT,
`user_id` int(5) NOT NULL,
`goal_description` varchar(100) NOT NULL,
PRIMARY KEY (`goal_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- Dumping data for table `goal_settings`
INSERT INTO `goal_settings` VALUES (1, 1, 'Run 1k');
INSERT INTO `goal_settings` VALUES (2, 1, 'Read 20 pages');
INSERT INTO `goal_settings` VALUES (3, 2, 'Cups of Coffee');
CREATE TABLE `checks` (
`check_id` int(40) NOT NULL AUTO_INCREMENT,
`goal_id` int(5) NOT NULL,
`check_date` date NOT NULL,
`check_count` int(3) NOT NULL,
PRIMARY KEY (`check_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- Dumping data for table `checks`
INSERT INTO `checks` VALUES (6, 1, '2012-03-02', 3);
INSERT INTO `checks` VALUES (2, 1, '2012-03-01', 2);
INSERT INTO `checks` VALUES (3, 2, '2012-03-01', 1);
INSERT INTO `checks` VALUES (5, 1, '2012-02-29', 1);
The output I'd like has goal_ids as rows and a range of dates as columns (like a week view calendar).
goal_id | 2012-03-01 | 2012-03-02 | 2012-03-03 | ... 2012-03-08 |
--------------------------------------------------------------------
1 2 3 0 ... 0
2 1 0 0 ... 0
Please note that when no checks exist for a given goal on a given day, 0 is returned instead of NULL.
I was able to get it working, poorly, using PHP. Truncated code, but I hope it shows basically what I tried: [$goal_ids is an array holding all goals associated with a user. $num_days is the number of days (i.e. columns) to be displayed, and $goal_days is an array used to hold the days we're looking to get info for].
$mysqli = new mysqli('xxx','xxx','xxx','goals');
$stmt = $mysqli->stmt_init();
$stmt = $mysqli->prepare("SELECT checks.check_count AS check_count
FROM `checks` WHERE goal_id = ? AND check_date = ?");
for($i=0; $i<=$goal_count - 1; $i++){
echo '<tr id="'.$goalid.'">';
for($j=0; $j <=$num_days; $j++){
$checkdate = $goal_days[$j];
$goalid = (integer) $goal_ids[$i];
if (!$stmt->bind_param("ii", $goalid, $checkdate)) {
echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}
$stmt->bind_result($check_count);
if($stmt->fetch()){
echo "<td>".$check_count."</td>";
}
else{
echo '<td>0</td>';
}
}
echo "</tr>";
}
echo "</table>";
$stmt->close();
This is obviously inefficient because for m goals and n days, it makes m x n select statements.
From reading, it seems like I'm basically trying to make a pivot table, but I've read that they are inefficient also, and I'm guessing what I'm doing is better handled by PHP than by doing a pivot table?
That leaves me with joins, which is what I think I'm asking for help with. I have considered creating a new column for every day, but I think it's not ideal. I'm open to totally changing the schema if necessary.
I hope I've been clear enough. Any help or pointers in the right direction would be greatly appreciated.
Thanks!
If I understand correctly your problem then I would suggest you should do a regular select in which each combination of goal_id and check_date will get a record in the result set, and then at the client side you will make a column for each check_date say by having an array of arrays and insert the checkcount in it.
This should at least be faster than having m x n select statements.
For more efficiency your sql can sort it by the goal_id and check_date, this will cause the records to be grouped together.
Here is an example of the sql statement:
SELECT check_date, goal_id, check_count FROM checks ORDER BY goal_id, check_date
Here is PHP sample code, assuming you have an array of arrays "$array_of_arrays" (initialized to zero to avoid the null problem) with the outer key being the goal_id and the inner key being the check_date:
while ($row = mysqli_fetch_result($result)){
$row_goal_id = $row["goal_id"];
$row_check_date = $row["check_date"];
$array_of_arrays[$row_goal_id][$row_check_date] = $row["check_count"];
}
And then you can use the array of arrays to do what you like, say for if you wish to output as an HTML table example then join the inner array with </td><td> and the outer array with </td></tr><tr><td>.
An example of how to create and initialize the "$array_of_arrays" array would be as follows (assuming you have an array $goals containing all the goals and an array $dates containing all the dates, if you don't know then in advance you can fetch them from the checks table by doing a SELECT DISTINCT)
$array_of_arrays = array();
foreach ($goals as $key=>$value){
$array_of_arrays[$value] = array();
foreach ($checks as $key1=>$value1){
$array_of_arrays[$value][$value1] = 0;
}
}
A similar approach can be used to generate the final HTML table as follows:
$final_array = array();
foreach ($array_of_arrays as $key=>$value){
$final_array[$key] = implode("</td><td>", $value);
}
$final_str = implode("</td></tr><tr><td>", $final_array);
$table_str = "<table><tr><td>" . $final_str . "</td></tr></table>";
Consider adding a table of days (or creating temporary one at runtime) holding just consecutive dates or dates you need. You could then get a nice list of check counts using a single query:
SELECT g.goal_id, d.day, COALESCE(c.check_count,0) as check_count
FROM
goal_settings g
JOIN
days d
LEFT JOIN
checks c
ON c.goal_id = g.goal_id AND c.check_date = d.day
WHERE
g.user_id = 1
AND d.day BETWEEN '2012-03-01' AND '2012-03-03'
ORDER BY g.goal_id, d.day
resulting in a rowset like:
goal_id | day | check_count
1 | 2012-03-01 | 2
1 | 2012-03-02 | 3
1 | 2012-03-03 | 0
2 | 2012-03-01 | 1
2 | 2012-03-02 | 0
2 | 2012-03-03 | 0
And then fetch those rows in a loop with php to build a nice html table - if goal_id changed then print new row and so on.

What is the correct syntax for INSERT INTO ... ON DUPLICATE KEY UPDATE in MySQL?

my table(s) structure (MySQL / each one is same as below)
+-------+--------------+------+------+-------------------+
| Field | Type | Null | Key | Default |
+-------+--------------+------+------+-------------------+
| id | int(11) | NO | PRI | AUTO INCREMENT |
| lesson| varchar(255) | NO | | LESSON_NAME |
| exam | char(50) | NO |UNIQUE| NO DEFAULT |
| quest | text | NO | | NO DEFAULT |
| answer| text | NO | | NO DEFAULT |
| note | text | NO | | NO DEFAULT |
+-------+--------------+------+------+-------------------+
and i'am posting some values to add this table via ajax ($post) - PHP 5.0
in database.php there is a function to get posted data and add to table
function update_table ($proper_table, $name, $question, $answer, $note) {
$sql = "INSERT INTO $proper_table (id, lesson, exam, quest, answer, note) VALUES ('', '', $name, $question,$answer,$note) ON DUPLICATE KEY UPDATE exam = $name, quest = $question, answer = $answer, note = $note";
$result= mysql_query($sql)or die(mysql_error());
}
$proper_table variable is taken by another variable to add this record to correct table.
(NOTE: Original table fields and variables are different (Turkish), to be more understandable i traslated to english but the syntax is the same as you see.)
Question : I want to check that if there is a record that exam field is same then all these variables will be used for updating this record, otherwise let function put this record to proper table as a new record.
But i'am getting error like below
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
is there any faulty coding? and what can be the solution?
Thanks right now...
function update_table ($proper_table, $name, $question, $answer, $note) {
$sql = "INSERT INTO $proper_table (lesson, exam, quest, answer, note) VALUES ('', '$name', '$question','$answer','$note') ON DUPLICATE KEY UPDATE quest = VALUES(quest), answer = VALUES(answer), note = VALUES(note)";
$result= mysql_query($sql)or die(mysql_error());
}
Just breaking this out I'll detail the changes
$sql = "INSERT INTO $proper_table
// Removed the PK (primary key) AI (auto increment) field - don't need to specify this
(lesson, exam, quest, answer, note)
// Likewise removed PK field, and added quotes around the text fields
VALUES ('', '$name', '$question','$answer','$note')
ON DUPLICATE KEY UPDATE
// If you specify VALUES(fieldName) it will update with the value you specified for the field in the conflicting row
// Also removed the exam update, as exam is the UNIQUE key which could cause conflicts so updating that would have no effect
quest = VALUES(quest), answer = VALUES(answer), note = VALUES(note)";
You need to wrap you string variables in single quotes in your SQL '$name' for example. Otherwise mysql thinks you are referencing column names.
With that query, when you add ON DUPLICATE KEY UPDATE... it will update when the id es the same than the id that you are sending, in this case you are not sending an id as parameter so it will never update because you have the id with auto-increment.
A solution could be that you read the table where exam equals the parameter you are sending, something like this:
SELECT id FROM $proper_table;
If it is null the you execute an insert, if it is not null the you update taking as parameter the id that you are getting from the select
id auto-increments, so presumably you don't want to set an empty string as id.
Try:
$sql = "INSERT INTO $proper_table (lesson, exam, quest, answer, note) VALUES ('', $name, $question,$answer,$note) ON DUPLICATE KEY UPDATE exam = $name, quest = $question, answer = $answer, note = $note";
You have to make it like this
<?php
function update_table($proper_table, $name, $question, $answer, $note, $id) {
$sqlQuery = "INSERT INTO '".$proper_table."' SET
name = '".$name."',
question = '".$question."',
answer = '".$answer."',
note = '".$note."' WHERE id = '".$id."'";
$result= mysql_query($sqlQuery)or die(mysql_error());
}
?>

How to add comma separated values to database as separate records?

I have a table named product_table as below with two fields product_id and comp_prod
The values for comp_prod will be sent as comma separated values like 4,3
but the value of product_id will be common
I want to insert the comma separated values as separate rows as follows with product_id as common. How can i do that using php and mysql ?
product_table
+-----+----------+-----------------+
| id | product_id |comp_prod |
+-----+----------+-----------------+
|1 | 339 | 4 |
|2 | 339 | 5 |
+------------+---------------------+
$pro=5;
$comp_proSplit= explode(",", $comp_pro);
$cnt=count($comp_proSplit);
for($i=0;$i<$cnt;$i++)
{
mysql_query("insert into product_table(product_id,comp_prod)
values ($pro, $comp_proSplit[$i])");
}
Hope it helps
Use explode function to split the string into array.
Use explode function
As the others mentioned, then loop it. Here is an example. There might be a mistake, but the idea is there.
foreach($arrayOfEachRowInCSV as $array){
$product_id = $array['product_id'];
$array_comp_prod = explode(",", $array['comp_prod_comma_seperated']);
foreach($array_comp_prod as $comp_prod){
$sql = "INSERT INTO table_name (product_id, comp_prod) VALUES('{$product_id}','{$comp_prod}')";
}
}
I hope this helps
$sql = array;
$yourArrFromCsv = explode(",", $yourCSV);
//then insert to db
foreach( $yourArrFromCsv as $row ) {
$sql[] = '('.$compProdId.', '.$row.')';
}
mysql_query('INSERT INTO table (comp_prod, product_id) VALUES '.implode(',', $sql));
Do you mean something like that

Categories