I am working on an android app which uses APIs made with php. Here, i am dynamically creating columns and their values.
I am verifying the API via postman and a strange thing happens every time, While looping through the Json Object what i am doing is first creating column and then inserting its values.
The problem is only the 1st iteration saves the element and rest of them only creates the column but does not insert the values. I don't know if i am doing anything wrong, below is my php code.
<?php
include("connection.php");
$data = file_get_contents('php://input');
$json_data = json_decode($data);
foreach($json_data as $key => $val) {
$column_name = $key ;
$c_column_name = preg_replace('/[^a-zA-Z]+/', '', $column_name);
$column_value = $val ;
$table_name = "test2";
$email = "ht#t.com";
$result = mysqli_query($conn,"SHOW COLUMNS FROM $table_name LIKE '$c_column_name'");
$exists = (mysqli_num_rows($result))?TRUE:FALSE;
if($exists) {
$query1 = "INSERT INTO $table_name($c_column_name)VALUES('$column_value') ";
$data0=mysqli_query($conn,$query);
if($data0)
{
echo json_encode(array("success"=>"true - insertion","message"=>"Column existed, Successfully data sent."));
}
else{
echo json_encode(array("success"=>"false - insertion","message"=>"Column existed, data not inserted."));
}
}
else{
$query2="ALTER TABLE $table_name ADD COLUMN `$c_column_name` varchar(50) NOT NULL";
$data1=mysqli_query($conn,$query2);
if($data1){
$query3="INSERT INTO $table_name($c_column_name)VALUES('$column_value')";
$data2=mysqli_query($conn,$query3);
if($data2)
{
echo json_encode(array("success"=>"true - insertion","message"=>"Successfully data sent."));
}
else{
echo json_encode(array("success"=>"false - insertion","message"=>"Column created but data not inserted."));
}
}
else
{
echo json_encode(array("success"=>"false - column creation","message"=>"Failed to create column.'$column_name', '$table_name', '$conn'"));
}
}
}
?>
Here is the Json Object through postman.
{"Shape":"rewq","Trans.No.":"yuuiop","Color":"qwert"}
Please help me with this, any help or suggestions are highly appreciated.
The second column name is Trans.No. which contains a dot, this is why it fails, probably you have an error as a result which prevents further columns from being created.
I think it would be much better to have a table with this structure:
attributes(id, key, value)
and whenever a key-value pair is received, you just insert/update it, depending on the logic you need to be executed. Your current model will create a separate row for each attribute, which is probably not what you want to achieve.
EDIT
Based on the information received in the comment section I reached the following conclusion:
You could create the missing columns first and then generate the insert statement with all the columns, having a single insert.
But it would be better to not create a separate column for each value, as the number of columns could quickly get out of hand. Instead you could have a table:
myentity(id, name)
for storing the entities represented by the JSON and
attributes(id, myentity_id, key, value)
for storing its attributes. This would be a neat schema with all the dinamicity you could want.
Related
I seem to be having trouble understanding the concept of how to properly use the information in a MySQL database using PHP/MySQLi. As I understand it, you generate a variable representing the connection object:
$connectionObject = mysqli_connect('serverString', 'userString', 'passString', 'databaseString');
then, generate a variable representing the query string you want to use:
$queryString = "SELECT rowName FROM tableName";
then, generate a variable representing the result object returned from a successful query:
$resultObject = mysqli_query($connectionObject, $queryString);
then, you use the fetch_assoc() function to generate an array from the result object and assign it to a variable:
$resultArray = myqli_fetch_assoc($resultObject);
then, you can use a while loop to (I have trouble with this one) to sort through the array and use the content of the row somehow:
while ($resultArray) {
echo $resultArray["rowName"];
}
Do I have this concept the wrong way, somehow, because its just not working for me, even to output the text content of a text-based CHAR(10) field with the contents of no more than: "BLAH".
The need to loop through the array to pick out the array item by name in the end anyway seems moot to me to begin with, but no matter where I look, I find the same concept.
My script code, minus a few key details, is:
if ($connectionObject=mysqli_connect("host0", "username0", "password0", "mysqldatabase0")) {
echo "Con";
}
if ($queryString="SELECT 'testdata' FROM 'testtable'") {
echo "Query";
}
if ($resultObject=mysqli_query($connectionObject, $queryString)) {
echo "Result";
}
if ($resultArray=mysqli_fetch_assoc($resultObject)) {
echo "Array";
}
while ($row=$resultArray) {
echo $row["testdata"];
print_r ($row);
}
mysqli_fetch_assoc returns an associate array of string representing the fetched row in the result set which is your $resultObject.
The problem is where you're using the while loop. You want to capture the returned associative array in a variable and access your data via that variable like follows:
while ($row = $resultArray) {
echo $row["rowName"];
}
To sort by rowName you can use the mysql order by clause in your query like follows which returns your results sorted by rowName:
$queryString = "SELECT rowName FROM tableName order by rowName";
Update after OP posted full code:
In your first if statement what would happen if the connection failed? You want to add some error handling there:
$connectionObject=mysqli_connect("host0", "username0", "password0", "mysqldatabase0"));
if (!$connectionObject) {
// exist out of this script showing the error
die("Error connecting to database " . mysqli_error($connectionObject));
} else {
// Don't really need this else but I'll keep it here since you already had it
echo "Con";
}
The problem is here You are using single quotes for column name and table name which are mysql identifiers. MySQL identifiers quote character is backtick not single quote.
Basically you need to use backticks if one of these identifiers are one of mysql reserved words (MySQL Reserved words), for other cases you don't need to use them.
Update your query:
if ($queryString="SELECT `testdata` FROM `testtable`") {
echo "Query"; // Leaving as is, not required
}
Lastly, an improvement. You want to add error handling here too:
if ($resultObject=mysqli_query($connectionObject, $queryString)) {
echo "Result"; // Leaving as is, not required
} else {
echo "Error executing Query " . mysqli_error($connectionObject);
}
Please note that when you use this script the error messages will be printed at the client i.e. when you use this script in a web application the errors will be shown in the user's browser. So you want to look into implementing logging and not printing them directly.
mysqli_fetch_assoc() returns one row as an associative array, of a mysqli_result object. Each time it is called, it returns the next row of results automatically and when used with a while loop, can be used to fetch an unknown number of result rows.
The $row['columnName'] is used to refer to the column. For example, if you had a person object with columns firstName, lastName, dateOfBirth, you could iterate through each person with a while loop as such:
while($row=mysqli_fetch_assoc($resultObject)){
$fname = $row['firstName'];
$lname = $row['lastName'];
$dob = $row['dateOfBirth'];
echo $fname . ' ' . $lname . ' ' . $dob;
}
This will echo details for a result returning an unknown amount of people.
Remember, calling the
if ($resultArray=mysqli_fetch_assoc($resultObject)) {
echo "Array";
}
before the while loop will skip the first result, so make sure the query returns multiple results when testing, as if you are only providing a resultObject containing one result, this might be why it isn't returning anything.
A better way to check if any results are returned is with the mysqli_num_rows($resultObject) function.
if(mysqli_num_rows($resultObject) > 0){
echo "Array";
}
Also not sure if it was just a typo but just to be sure, in your query you are selecting columnName not rowName:
$queryString = "SELECT columnName1(eg. firstName), columnName2(eg. lastName) FROM tableName";
I just recently started learning PHP, and the mysqli_fetch_assoc function confused me too, so I hope this helps!
I am trying to make a database of Users. One user can have an indefinite number of phone numbers. So in the form I’ve created a js function that will give me new input fields and they put the information into a nestled array.
I am doing a double foreach loop to go through my array, and add SQL queries to it based on if the id already exists and just needs to be updated or if it's entirely new and needs to be inserted. I add these SQL queries to a variable $phoneSql . When I echo that variable, it does contain a valid SQL query which works if I try it directly in phpMyAdmin.
This is the foreach loop code:
$phoneSql = 'SELECT id FROM user WHERE id = '.$id.' INTO #id;';
foreach($_POST['phone'] as $key => $value) {
foreach($_POST['user'][$key] as $id => $number) {
if($id == 0 && !$number == ''){
$phoneSql .= 'INSERT INTO phone_number (id, user_id, number) VALUES (NULL, #id, "'.$number.'");';
} else if (!$number == '') {
$phoneSql .= 'UPDATE phone_numbers SET user_id = #id, number = "'.$number.'" WHERE id = '.$id.';';
}
}
}
I have one edit.php page with the form, which posts to update.php where I have the foreach loop from above and following code:
$db->updatePhoneNumber($phoneSql);
It also gets the $id from the user I’m editing at the moment. Then it gets sent to db.php and into this function:
public function updatePhoneNumbers($phoneSql) {
$ phoneSql = $ phoneSql;
$sth = $this->dbh->prepare($phoneSql);
$sth->execute();
if ($sth->execute()) {
return true;
} else {
return false;
}
}
But this is not working. Can I add a variable with sql queries into a function like that or do I have to do it some other way? I’m quite new to this so I’m not sure how to proceed. I’ve tried searching for a solution but haven’t found any. I’m thankful for any advice.
What you should be doing is using an INSERT ... ON DUPLICATE KEY UPDATE ... construct, saving you a lot of that logic.
e.g.
INSERT INTO phone_number (id, user_id, number) VALUES (...)
ON DUPLICATE KEY UPDATE user_id=VALUES(user_id), number=VALUES(number)
With this, no need to select, test, then insert/update. You just insert, and MySQL will transparently convert it into an update if a duplicate key error occurs.
I have one problem here, and I don't even have clue what to Google and how to solve this.
I am making PHP application to export and import data from one MySQL table into another. And I have problem with these tables.
In source table it looks like this:
And my destination table has ID, and pr0, pr1, pr2 as rows. So it looks like this:
Now the problem is the following: If I just copy ( insert every value of 1st table as new row in second) It will have like 20.000 rows, instead of 1000 for example.
Even if I copy every record as new row in second database, is there any way I can fuse rows ? Basically I need to check if value exists in last row with that ID_, if it exist in that row and column (pr2 for example) then insert new row with it, but if last row with same ID_ does not have value in pr2 column, just update that row with value in pr2 column.
I need idea how to do it in PHP or MySQL.
So you got a few Problems:
1) copy the table from SQL to PHP, pay attention to memory usage, run your script with the PHP command Memory_usage(). it will show you that importing SQL Data can be expensive. Look this up. another thing is that PHP DOESNT realese memory on setting new values to array. it will be usefull later on.
2)i didnt understand if the values are unique at the source or should be unique at the destination table.. So i will assume that all the source need to be on the destination as is.
I will also assume that pr = pr0 and quant=pr1.
3) you have missmatch names.. that can also be an issue. would take care of that..also.
4) will use My_sql, as the SQL connector..and $db is connected..
SCRIPT:
<?PHP
$select_sql = "SELECT * FROM Table_source";
$data_source = array();
while($array_data= mysql_fetch_array($select_sql)) {
$data_source[] = $array_data;
$insert_data=array();
}
$bulk =2000;
foreach($data_source as $data){
if(isset($start_query) == false)
{
$start_query = 'REPLACE INTO DEST_TABLE ('ID_','pr0','pr1','pr2')';
}
$insert_data[]=implode(',',$data).',0)';// will set 0 to the
if(count($insert_data) >=$bulk){
$values = implode('),(',$insert_data);
$values = substr(1,2,$values);
$values = ' VALUES '.$values;
$insert_query = $start_query.' '.$values;
$mysqli->query($insert_query);
$insert_data = array();
} //CHECK THE SYNTAX IM NOT SURE OF ALL OF IT MOSTLY THE SQL PART>> SEE THAT THE QUERY IS OK
}
if(count($insert_data) >=$bulk) // IF THERE ARE ANY EXTRA PIECES..
{
$values = implode('),(',$insert_data);
$values = substr(1,2,$values);
$values = ' VALUES '.$values;
$insert_query = $start_query.' '.$values;
$mysqli->query($insert_query);
$insert_data = null;
}
?>
ITs off the top off my head but check this idea and tell me if this work, the bugs night be in small things i forgot with the QUERY structure, print this and PASTE to PHPmyADMIN or you DB query and see its all good, but this concept will sqve a lot of problems..
I am hoping to remove duplicate entries from an array that I am calling from a stored procedure with a while loop.
// Prepare stored procedure call
$sth = $dbh->prepare('CALL sp_get_recipes()');
// Call the stored procedure
$res = $sth->execute();
if ($res){
while( $row = $sth->fetchObject() ){
echo $row->Recipe; // I would like to echo this row just once.
echo '<ul class="recipe-body"><li>'.$row->Ingredient." ".$row->Quantity." ".$row->UoM.'</li></ul>';
}
// Close connection
$dbh = null;
}else{
$arr = $sth->errorInfo();
echo "Execution failed with MYSQL: " . $arr[0] . "\n";
die();
}
My understanding is my echo $row->Recipe; has to exist on it's own somehow. I've being looking into array_unique to echo the value just once but I can't seem to figure it out exactly. If someone could point me in the right direction it would be great.
UPDATE
Thanks for all the responses I have fixed up the stored procedure to return unique rows.
Create a temporary array before the while and store every Recipe in it which have been echoed. Before the echo check the temporary array for the current Recipe (if it contains don't echo it otherwaise echo & store it in the temporary array).
If you cannot change the database structure, which I would recommend, you could first store the information you get from the database query into objects (e.g. some kind of Recipe objects with an array of Ingredient objects) and then build your actual output.
If you can change the database structure or the way you query (if the latter already gives you what I'm about to recommend) you can have a table (assuming the database is relational) for the recipes with some kind of ID and another table for the ingredients of the recipes where each ingredient row also stores the ID of the recipe it belongs to.
I'm trying to add iterate through an object and add those object properties to mysql database. Using:
//This works
$sql = "CREATE TABLE $table ($ID int primary key auto_increment not null)";
mysql_query($sql);
//This works
function iterateObject($obj, $name='') {
foreach ($obj as $key=>$val) {
$myName = ($name !='') ? $name . "_" . $key : $key;
if ( is_object($val) || is_array($val) ) {
iterateObject($val, $myName);
} else {
//This works
$sql = ("ALTER TABLE home_timeline ADD COLUMN $myName VARCHAR(256);");
mysql_query($sql);
//This doesn't work
$sql2 = ("INSERT INTO home_timeline ($myName) VALUES ($val);");
mysql_query($sql2);
print "$myName - $val <br />";
}
}
}
The table is created and altered so that each iteration adds a new column to the table but when I try and add values to that column (second sql statement) everything is null and the script creates 20+ rows rather than having all the values appear on one row in the relevant column. Could someone help?
why not use functions like serialize() and unserialize() when converting objects to/from string?
second: if $val is string, then in the query put the string delimiters
"INSERT INTO home_timeline (`$myName`) VALUES ('$val');"
though inserting parameters via concatenation is a very bad practice prone to SQL injection.
If you have further problems, output the query before execution and put it here. You might be experiencing the case when you got a lot of columns which can't be nulls, and have no default values. Also output the table structure here.