Send delimited string via JSON to PHP for prepared statements - php

For example i send the following id:
$user->id = '1{3}4{5}6';
Represents:
$user->id(=1{3}4{5}6){$option(=3)}$value(=4){$option(=5)}$value(=6)
I now need to insert to database using prepared statements for each $option and $value pair.
the sql looks as following:
if ($user->attr == 1) {
$sth = $this->dbh->prepare("insert into customers_basket_attributes
(customers_id,
products_id,
products_options_id,
products_options_value_id)
values ('1', ?, ?, ?)");
$sth->execute(array($user->id, $option, $value));
return json_encode(1);
}
I want to avoid falling back to jQuery for each db insertion.

as far as I understand, this $user->id = '1{3}4{5}6'; decomposes:
Product_id = 1
Option_3 = 4
Option_5 = 6
and you want to store that in to records like:
products_id products_options_id products_options_value_id
1 3 4
1 5 6
From my point of view, you basically need as much inserts as you have rows above. You may combine that in to one insert with multiple rows:
insert into customers_basket_attributes
(customers_id,
products_id,
products_options_id,
products_options_value_id)
values (nn, 1,3,4),(nn, 1,5,6)
putting this into a prepared statement is somehow fiddling around with arrays, but should be achievable. Probably its clearer to just issue one insert per row, the cost is marginal anyway.

Related

Running an insert script from multiple values

I'm trying to run a pretty simple script that does the following: Takes the id of a content module and assigns it to multiple locations
So say I click the link on a content module with ID of 123, I want to assign it to all multiple locations. In SQL I would just say :
INSERT INTO table (cont_id,loc_id)
VALUES (123, select(id from location_table where active = 1))
I'm currently using this:
$pageID = $_GET['pageID'];
$assignPage = "
INSERT INTO locationContent(page_id, display_id)
VALUES ( '$pageID', select(id from locations where active = 1))
ON DUPLICATE KEY UPDATE active = 1
";
$performAssign = $mysqlConn->query($assignPage);
The issue I'm wondering about though, is do I need to put this into a foreach or while loop? If I were to just run as is, I feel like that would only work for one record
You seem to be looking for MySQL INSERT ... SELECT syntax.
From the documentation:
With INSERT ... SELECT, you can quickly insert many rows into a table from the result of a SELECT statement, which can select from one or many tables.
Query:
INSERT INTO locationContent (page_id, display_id)
SELECT ?, id FROM locations WHERE active = 1
ON DUPLICATE KEY UPDATE active = 1
The ? stands for parameter $pageID (you do want to use parameterized queries and prepared statement to protect your code against SQL injection).
You can't mix the INSERT INTO .. VALUES and INSERT INTO ... SELECT syntax, however SELECT constant, var FROM .. is possible like:
$assignPage = $mysqlConn->prepare("
INSERT INTO locationContent(page_id, display_id)
SELECT :page as page_id, id FROM locations WHERE active = 1
ON DUPLICATE KEY UPDATE active = 1
";
$performAssign = $assignPage->execute(array('page' =>$pageID));

php mysqli repeated fields in prepared statement

I need to convert an existing project from mysql to mysqli and using prepared statement.
In the existing project there are queries that uses repeated variable values.
One such example is this: where the $prev_yr is used 3 times.
$sqlins = "Insert into studentclass (`StudentID`, `ClassID`, `Year`, `Level`, `SNo`, `TermList`, `DateStart`, `DateEnd`)
select StudentID, '$prev_cl', '$prev_yr', '$prev_lvl', '', '123456789', '$prev_yr-01-01', '$prev_yr-12-31' from student Where StudentID in ($ids) ";
Is there a better method than this:
$sqlins = "Insert into studentclass (`StudentID`, `ClassID`, `Year`, `Level`, `SNo`, `TermList`, `DateStart`, `DateEnd`)
select StudentID, '?', '?', '?', '', '123456789', '?-01-01', '?-12-31' from student Where StudentID in (?) ";
$stmt = $mysqli->prepare($sqlins);
$stmt->bind_param("ssssss", $prev_cl,$prev_yr,$prev_lvl,$prev_yr,$prev_yr,$ids);
$stmt->execute();
I am wondering if there is a way of binding the $prev_yr once for all 3 occurrences.
Because there are other queries that may have 2 occurrences of $prev_lvl, 5 occurrences of $prev_yr etc in one statement. The idea is that when the repeated occurrences of multiple variables becomes many in a statement - it becomes quite confusing to arrange them in the bind_param.
Any solution?
Thank you.
Does it even work like that, typical you wont't do this '?-01-01' in a query. I haven't used Mysqli, in about 4 years, as all I use now a days is PDO. But as far as I know when you send that to prepare it's gonna puke on the ? being in a string.
I would split it, there actually is no real need to do the select because the only thing being selected is the studentID which you already have. Simply
$insert = $mysqli->prepare("Insert into studentclass (`StudentID`, `ClassID`, `Year`, `Level`, `SNo`, `TermList`, `DateStart`, `DateEnd`)VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
foreach( $ids AS $id ){
$stmt->bind_param("issssiss", $id, $prev_cl,$prev_yr,$prev_lvl,'', '123456789', $prev_yr.'-01-01',$prev_yr.'-12-31');
$stmt->execute();
}
I can't test it so hopefully I got everything in the right place.
As I said I don't think you can bind to the Fields part of the query and certainly not inside a partial string, besides it's making a select that is un-needed. Just make sure to prepare the insert before the loop.
Just to clearly the only thing that select actually gets from the DB is this
select StudentID ... from student Where StudentID in (?)
The rest are added in as "fake" columns, I don't know the term for it. It's difficult to read the original query..
I am wondering if there is a way of binding the $prev_yr once for all 3 occurrences.
No.
Besides, it wouldn't work this way anyway, as you cannot bind just an arbitrary query part of your choice. You can bind a complete data literal only. Means instead of '?-01-01' it should be just ?, whereas in your PHP code you should make it
$dateStart = "$prev_yr-01-01";
and then bind this variable for the whole value. So there will be no more repeating variables.

PHP / MySQL: How to use INSERT INTO only if certain condition is met

I am new to MySQL and hope someone can help me with this.
I currently use the following as part of a longer statement in PHP in order to write something to a db table which works as intended:
$stmt = $conn->prepare("INSERT INTO History (email, year, halfYear, language, content) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("siiss", $email, $year, $halfYear, $language, $content);
$stmt->execute();
$result = $stmt->get_result();
How can I check if the corresponding email address ($email) already has 3 entries in the db and only write in the db when it has 2 or less entries (otherwise I just want to echo something) ?
I was thinking I could use something like $result->num_rows but wasn't sure how to apply this here.
Can someone help me with this ?
Many thanks in advance,
Mike
As per requested by the OP.
You first need to count the results in a SELECT all set inside a conditional statement.
If the query matches the criteria, perform the next one.
Example using num_rows:
if($result->num_rows == 3){
// do something
}
else {
// do something else
}
or num_rows >= 3 should you want to check if equal and/or more than 3 also.
Reference:
http://php.net/manual/en/mysqli-result.num-rows.php
Sidenote:
Be careful with your use of year it is a MySQL reserved keyword:
https://dev.mysql.com/doc/refman/5.5/en/keywords.html
You can still use it, but just as long as you wrap it in ticks.
I.e.:
(email, `year`, halfYear, language, content)

PHP/MySQL Insert null values

I'm struggling with some PHP/MySQL code. I am reading from 1 table, changing some fields then writing to another table, nothing happens if inserting and one of the array values is null when I would like it to insert null in the database (null values are allowed for the field). It looks a bit like this:
$results = mysql_query("select * from mytable");
while ($row = mysql_fetch_assoc($results) {
mysql_query("insert into table2 (f1, f2) values ('{$row['string_field']}', {$row['null_field']});
}
Not every row has a null value and in my query there are more fields and 2 columns which may or may not be null
This is one example where using prepared statements really saves you some trouble.
In MySQL, in order to insert a null value, you must specify it at INSERT time or leave the field out which requires additional branching:
INSERT INTO table2 (f1, f2)
VALUES ('String Value', NULL);
However, if you want to insert a value in that field, you must now branch your code to add the single quotes:
INSERT INTO table2 (f1, f2)
VALUES ('String Value', 'String Value');
Prepared statements automatically do that for you. They know the difference between string(0) "" and null and write your query appropriately:
$stmt = $mysqli->prepare("INSERT INTO table2 (f1, f2) VALUES (?, ?)");
$stmt->bind_param('ss', $field1, $field2);
$field1 = "String Value";
$field2 = null;
$stmt->execute();
It escapes your fields for you, makes sure that you don't forget to bind a parameter. There is no reason to stay with the mysql extension. Use mysqli and it's prepared statements instead. You'll save yourself a world of pain.
I think you need quotes around your {$row['null_field']}, so '{$row['null_field']}'
If you don't have the quotes, you'll occasionally end up with an insert statement that looks like this: insert into table2 (f1, f2) values ('val1',) which is a syntax error.
If that is a numeric field, you will have to do some testing above it, and if there is no value in null_field, explicitly set it to null..
For fields where NULL is acceptable, you could use var_export($var, true) to output the string, integer, or NULL literal. Note that you would not surround the output with quotes because they will be automatically added or omitted.
For example:
mysql_query("insert into table2 (f1, f2) values ('{$row['string_field']}', ".var_export($row['null_field'], true).")");

INSERT new rows, UPDATE old rows: how?

I am making a PHP utility that imports and analyzes a CSV file into $data, and whether or not to INSERT "new" rows into the database ($saveNew).
Right now, I have a bit of an ugly mess: (in generalized pseudo-PHP)
function synchronize($data,$saveNew) {
$existing_ids = $table->find_all('ID'); //array of ID's in the table
$incoming_ids = get_key('ID',$data); //grabs the ID field from each record
$new_ids = array_diff($incoming_ids,$existing_ids);
foreach ($data as $record) {
if (in_array($record['ID'],$new_ids)) { //it's new
if ($saveNew) $table->insert($record);
else continue;
} else {
$table->update($record);
}
}
}
To me, this just has a smell, and I think I could accomplish this in just a single query, except that I'm not that familiar with SQL.
I'm using a simple ORM in my app, but I can easily just use straight SQL.
Oh, and I'm using MySQL.
Can this be done with just one query? It seems like this would be a common problem with a simple solution, but I just can't figure it out.
Have a look at MySQL's INSERT ... ON DUPLICATE KEY ... syntax, which allows you to do just that: http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html
Whether you want to implement that in your ORM or in that specific subroutine of yours is up to you...
If you have a unique row identifier, you can use the INSERT ... ON DUPLICATE KEY UPDATE syntax:
INSERT INTO foo (id, col1, col2) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col1 = VALUES(col1), col2 = VALUES(col2);
Then, when you bind NULL, 4, 5 it'll insert a new row (assuming id is an autoincrement column)
When you bind 1, 4, 5 it'll insert a new row if there is no row 1, otherwise it'll update row 1's col1 and col2 fields to 4 and 5 respectively...

Categories