Dynamic SQL Inserts for JSON data [PHP] - php

Near daily I am tasked with inserting JSON data into a relational database via PHP, as is with JSON data some records with have certain columns while others do not, and this tends to be a problem when inserting into a table.
If I am inserting several thousands students a record might look like
{"name": "Billy Jackson", "Height": 172, "DOB" : "2002-08-21"}
However its not certain that height and or DOB is set in any record, what I currently do is something like
<?php
foreach($records as $json){
$name = addslashes($json['name']);
if(isset($json['Height']){
$height = $json['Height'];
}
else{
$height = "NULL"
}
if(isset($json['DOB']){
$dob = $json['DOB'];
}
else{
$dob = "NULL"
}
}
$db->query("INSERT INTO table (name, height, dob) VALUES ('$name', $height, '$dob')");
As you may see this is not elegant nor does it work for several types, fields like DOB do not accept NULL, nor do enums.
Is there a more elegant built in solution, to only try and insert into columns where the value exists in the JSON.
Is this something prepared statements handle?
EDIT
lets say the example record above did not have DOB setthe insert statement would look like
"INSERT INTO table (name, height, dob) VALUES ('Billy Jackson', 172, 'NULL')"
Which fails, if have $dob be set to null ($dob = null) if it is not set then the insert statement looks like
"INSERT INTO table (name, height, dob) VALUES ('Billy Jackson', 172, '')"
Which fails
Why even include the dob column? because some records do have a dob and I want them included in the insert

Empty string '' is not the same as null. Nor is the string "null". Since your query explicitly quotes the contents of the $dob variable, you're quoting the string null such that it becomes "null" which is definitely not null. :)
To avoid the need to mess with quotes (and SQL injection), you'll want to use a prepared statement, something like this:
$db->prepare('INSERT INTO table (name, height, dob) VALUES (?, ?, ?)');
Then when you bind the values, PHP will automatically take care of what fields need quotes and which don't.
Also note, you can shortcut this:
if (isset($json['Height']){
$height = $json['Height'];
} else {
$height = "NULL"
}
Into just this:
$height = $json['Height'] ?? null;
Which would eliminate a bunch of your code and make your bind something like this:
$stmt->bind_param(
'sis',
$json['name'],
$json['Height'] ?? null,
$json['dob'] ?? null
);

You should start with addressing the problems in your table design.
All columns that MUST have data should be set to NOT NULL, and a default value set, if appropriate. It may not be appropriate to have a default value for User Name, for example, so don't set one.
All columns that MIGHT have data should be set to accept NULL, with a default value set as appropriate. If there's no data then the correct value should generally be NULL and that should be set as a default.
Note that both DATE and ENUM columns can accept NULL if properly configured.
Once you have your column definitions correct you can generate an INSERT query based on the actual values you find in your JSON file. The data integrity rules you set in your table definition will ensure that appropriate values are entered for any row that is created with values missing, or that the row is not created if 'must have' data is missing.
This leads to some code like this, based on PDO prepared statements:
$json = '{"name": "Billy Jackson", "Height": 172, "DOB" : "2002-08-21"}';
$columnList = [];
$valueList = [];
$j = json_decode($json);
foreach($j as $key=>$value) {
$columnList[] = $key;
// interim processing, like date conversion here:
// e.g if $key == 'DOB' then $value = reformatDate($value);
$valueList[] = $value;
}
// Now create the INSERT statement
// The column list is created from the keys in the JSON record
// An array of values is assembled from the values in the JSON record
// This is used to create an INSERT query that matches the data you actually have
$query = "INSERT someTable (".join(',',$columnList).") values (".trim(str_repeat('?,',count($valueList)),',').")";
// echo for demo purposes
echo $query; // INSERT someTable (name,Height,DOB) values (?,?,?)
// Now prepare the query
$stmt = $db->prepare($query);
// Execute the query using the array of values assembled above.
$stmt->execute($valueList);
Note: You many need to extend this to handle mapping from JSON keys to column names, format changes in date fields, etc.

Related

How to make PHP MYSQL Insert query only with values which are existed for certain columns?

I have 17 columns in my DB
I'm inserting values from different sources. Somewhere I haven't, for example, company/company_info values (I'm setting in PHP FALSE values for relevant variables).
So, I need some kind of PHP INSERT query to insert only not empty variables and columns of certain list.
For example, I could do:
$q = "INSERT INTO `$tname` (`phone`,`location`, `pagelang`, `company`, `company_url`, `phone_no_cc`, `phone_type`, `operator`, `pageviews`, `rating`, `comments_number`, `activity_by_days`, `activity_by_hours`) VALUES (
'$main_number', '$number_advanced_info[location]', '$pagelang', '$company[name]', '$company[site]', '$number_advanced_info[number_no_countrycode]', '$number_advanced_info[phone_type]', '$number_advanced_info[operator]', '$searches_comments[searches]', '$rating', '$searches_comments[comments]', '$history_search', '$daily_history'
);";
With insert of 14 columns and their values.
But sometimes I need to insert less columns/values and let MYSQL set default values for not listed columns. For Example, I want to insert only 5 columns.
$q = "INSERT INTO `$tname` (`phone`,`location`, `pageviews`, `rating`) VALUES (
'$main_number', '$number_advanced_info[location]', '$searches_comments[searches]', '$rating'
);";
Is there some CLASS or any solution like binding values which will automatically build query depending which values are not NULL?
I need some kind of code:
if (!$phone) {
$columns .= "`column_name`," ;
$values .= "value";
}

PDO json insert multiple tags

I've been trying to insert some tags into a table using pdo but to no avail.
I have a php array called Tag.
Sample data in tag array is as follows
tag[] = [[a,b,c,d,e],[f,g,h,i,j]]
using a for loop below I'm able to convert it to (1,'a','b','c','e',0), (1,'f','g','h','i',0)
$value="";
$value .= "($postid,";
for($i=0;$i<sizeof($tag);$i++)
{
$value .="'$tag[$i]'";
if($i + 1 == $sizeof($tag){
$value .=")";
}else{
$value .="),";
}
}
And prepare and insert into the table as follows
$inserttagquery = "insert Into tagtable ( postid, desc, b, u, toppos,leftpos ,ver) values :value";
$queryinserttag = $conn->prepare($inserttagquery);
$queryinserttag->execute(array('value'=>$value));
$insertedtag = $queryinserttag->rowCount();
However, this does not seem to work. $insertedtag does not return any value.
Your SQL is outright wrong. You're lising 6 fields AND a constant value in your field list, then providing only a SINGLE placeholder to provide values for those fields.
you cannot use numbers as a field name. 0 is a flat out syntax error and an invalid field name.
Placeholders have a 1:1 relation between a field and a value. You CANNOT shove multiple values into a single variable and try to use that value with a placeholder to fill in OTHER fields.
Your query should be:
INSERT INTO tagtable (postid, desc, b, u, etc...)
VALUES (:postid, :desc, :b, :u, etc...)
and then you provide INDIVIDUAL values for each placehodler:
$stmt->execute(array($postid, $desc, $b, $u, etc...));
As written, and ignoring all the other problems, your query would try shove your (1, 'f', 'g', etc..) string into JUST the postid field.

I cannot get default in sql to work

I am having an issue with sql right now; I have gave a value a default so if the field is left empty when the user submit, but it is not working. When the user submits an empty field to leave a comment instead of it default to anon it does nothing. Also, in the datebase the field is empty.
name VARCHAR (50) default 'anon',
$name= $_POST['name'];
$title= sha1($_POST['title']);
$texts= $_POST['texts'];
$forum_id = $_POST['forum_id'];
$name = str_replace("'","''",$name);
$title = str_replace("'","''",$title);
$title = str_replace("b074acd521","STREAMER",$title);
$texts = str_replace("'","''",$texts);
$title = substr($title,0,8);
$sql = "INSERT INTO post (name,title, texts, forum_id) VALUES ('$name', '$title', '$texts', '$forum_id')";
mysqli_query($conn1, $sql) or die('Error inserting to database.');
mysqli_close($conn1);
header('Location: requests.php');
Is there another way to do it or am I just doing something wrong?
The SQL query your using will not insert the default value from your database because you are specifying a value for name (even if that value is an empty string, or null) :
$sql = "INSERT INTO post (name,title, texts, forum_id) VALUES ('$name', '$title', '$texts', '$forum_id')";
Instead if you want the default value to be inserted into the name field you must not specify the name column in the insert statement :
$sql = "INSERT INTO post (title, texts, forum_id) VALUES ('$title', '$texts', '$forum_id')";
In SQL query you can specify for which fields, values will be provided in the query and remaining fields from the table would contain default value (in case of AUTO_INCREMENT, the next integer value will be used).
Where you given the default value directly applied in SQL? the value left in DB ultimately is what exactly you passed to DB server by SQL way, or just you defined a variable where if it don't accept a value from user then use the default value instead, please try to debug this to insure the value was handled correctly.
while insert the values you shouldn't give the column which you set default value
below Example explain it...Try like this...
create table er(id int,name char(10),gender char(2)default 'M')
Here i took gender as default
now i insert the values
insert into er (id,name)values(1,'poda')
select * from er

MYSQL - INSERT INTO from left

First of all thanks for your help, I'm asking how can I insert data into fields starting from the left? Depending on the entity sometimes several fields at the end are left blank but I need to insert the filled fields into the table. If I try to do this, I obviously get a column-values mismatch error.
Thanks!
The column count you use and the number of values you try to insert have to match. You can specify what you want to insert, so you don't have to pass the columns which aren't needed (and so you don't need to pass "blanks").
INSERT INTO Store_Information (store_name, Sales, Date)
VALUES ('Los Angeles', 900, 'Jan-10-1999')
More information:
http://www.1keydata.com/sql/sqlinsert.html
Just specify only fields names you gonna insert at the moment:
INSERT INTO table (field1, field2, field3) VALUES (value1, value2, value3)
or this way
INSERT INTO table SET field1=value1, field2=value2, field3=value3
no matter is it from left, right or checkered
as SQL query is just a string, you could use some PHP code to build this string in the way you want.
hereis an example code in the form of very simple helper function to produce SET statement dynamically:
function dbSet($fields) {
$set='';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
return substr($set, 0, -2);
}
it can be controlled by $fields array.
used like this
//if we have full set of data
$fields = explode(" ","name surname lastname address zip fax phone");
$query = "INSERT INTO $table SET ".dbSet($fields);
//if we have only three fields ready
$fields = explode(" ","name surname lastname");
$query = "INSERT INTO $table SET ".dbSet($fields);
but you desperately need to learn basic PHP string operations to be able to do such things yourself.
string operations are most important in PHP, as almost every task for PHP is just string manipulation like in your case.
Use querys like
insert into table set col1=val1, col2=val2;
or
insert into table(col1, col2) values(val1, val2);
That is the only way around it. I think method 2 is the most commonly used.
If there is any way you can supply default values for each column use them for the columns you don't have values for.
if all the data can be "NULL", you can setup your query with variables that, if not set, are NULL, example:
$col1 = null;
$col2 = null;
$col3 = null;
$col4 = null;
$col5 = null;
then populate the columns you need
$col1 = 'val1';
$col2 = 'val2';
$query = "INSERT INTO (col1, col2, col3, col4, col5) VALUES ($col1, $col2, $col3, $col4)";
Sincerely I'll never use something like this... but you asked for it...
mysql_query("INSERT INTO People (First_Name, Last_Name, Age)
VALUES ('Marcus', 'Porter', '28')");
mysql_query("INSERT INTO People (First_Name, Last_Name, Email)
VALUES ('Marcin', 'Kruk', 'marcin.kruk#gmail.com')");

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).")");

Categories