How to select by condition on JSON column in MySQL? - php

How to write query for selecting data by where condition on column having JSON array?
i.e.
Suppose I have added user_name, user_role in ci_sessions. and user_data is JSON array.
SELECT *
FROM `ci_sessions` where user_data[user_role]='admin';
*********************/\***************
This where condition is needs to be designed. I require data with having user_role "admin".
Update: To check user_role "admin" is main objective of where condition.
Is there any way to add where condition as user_data[user_role] or user_data->user_role?
Update: This is possible in PostgresSQL DB.

Don't know what you're doing there, but you just call $this->session->userdata('user_role') and CI's automatically chooses how to retrieve that value. If you set (and I think you did) to use a database, the query will be performed automatically.
I don't understand how you actually saved your session variable, if you json_encoded() by yourself or you are referring to the encoding performed by CI.
In the latter, you just:
if($this->session->userdata('user_role') == 'admin')
{
// do stuff
}
Otherwise, $role = json_decode($this->session->userdata('user_role')); and the examine the array but I can't help you much here since you didn't provide clear information

I was keep on waiting for this type of query but I failed to do so. That's why I had made combination of sql and php.
I have got results from all ci_sessions table.
Then I checked in result by decoding field of JSON arraY. aND it's working fine.
SELECT * FROM `ci_sessions`;
foreach ($result as $row) {
$user_data=$row->user_data;
foreach (unserialize($user_data) as $k => $v) {
$final[] = array('key' => $k, 'value' => $v);
if($k=='user_role' && $v='admin') {
//make array of admin information required to show
}
}
}

Related

Insert Json object to database in php

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.

PHP/MySQL - Update array if variable does not exist

I have an array with different IDs which I get from my database.
$fotos_temp_list=explode(",",$fotos_temp["fa_id"][0]);
Result: fa_id => 15,16,17,18
Now I want to update all rows inside another table with the IDs 15,16,17,18 and insert a specific '$id' into a column called 'fa_ev_id'.
In this example I set:
$id=1;
Now my foreach-loop looks like this:
foreach ($fotos_temp_list as $key) {
UPDATE images SET fa_ev_id = Concat(fa_ev_id , ',' ,'".$id."') where fa_id='".$key."' ";
}
This part is working too.
Every row with my IDs (in my example: 15,16,17,18) gets updated.
Problem:
When I run the foreach-loop again, the '$id' will be saved again inside the row. See here:
Question:
How is it possible, that I can check if '$id' is already inside the row and if so, it gets skipped? Here is what I tried to do:
foreach ($fotos_temp_list as $key) {
if (!in_array($id,$key)===true) {
UPDATE fotoalbum SET fa_ev_id = Concat(fa_ev_id , ',' ,'".$id."') where fa_id='".$key."'
}
}
I think the in_array function checks if '$id' id already inside '$key' and if it is true, the UPDATE statement is done. Therefore I added '!in_array' but it doesn´t seems to work. Does anyone has an idea what I am doing wrong? I just want to check if the '$id' is already inside my database row and if so, it should not insert the '$id' again.
I appreciate any advice.
The in_array() function in php accepts an array as its second parameter, in (!in_array($id,$key)===true), https://www.w3schools.com/php/func_array_in_array.asp. The second parameter $key, passed in here isn't an array.
You could save the datatype of fa_ev_id as json, and retrieve and json_decode the value when you are about performing an update the field to know if that $id already exists using in_array() or you could retrieve the values, expolode them to form an array and then check if it exists with in_array().

How could I optimize the following piece of code?

$project_query= $db->query("SELECT * FROM projects WHERE id='$task_info->project_id'");
$project_info = $project_query->fetch_object();
$admins_array = $project_info->admins_array;
$admins = unserialize($admins_array);
$is_admin = false;
foreach($admins as $value) {
if($value == $_SESSION['username']) { $is_admin = true; }
}
I have the following code that checks if the currently logged user's username is contained in a serialized array that is stored in a mysql table row. How would I go about optimizing it for maximum performance?
1) if changing your db structure is a possibility, I suggest storing the serialized values in a separate table
project_admins (project_id, user_id) with a unique index on (project_id,user_id)
Then you can quickly determine whether a user is an admin of a project
SELECT 1 from project_admins where project_id = x and user_id = y
2) if you're stuck with storing serialized data in the db I suggest storing the serialized array indexed by username
so you can search it in constant time
i.e.
$is_admin = array_key_exists($_SESSION['username'],$admins);
3) if you can not index the admins array by username, you can minimally optimize your loop by adding a break statement once you find a match
foreach($admins as $value) {
if($value == $_SESSION['username']) {
$is_admin = true;
break; // match found no need to check remaining values
}
}
Actually in this case you're probably better off using in_array
$is_admin = in_array($_SESSION['username'],$admins);
If it's optimization in terms of speed, then I would suggest performing the login in SQL.
It would require you to change your table structure to a more normalised state by switching from serialised strings into separate related entities.

Updating database according to check-boxes checked

I've the following table layout in my database with some data.
I'm taking input by check-boxes so user can select all applicable accident road conditions and it to database. I would say it is okay if you're adding a new record you just loop through the checkboexs checked and insert them in DB
The first information is now saved in the database, now user decided to change the road conditions for any reasons user came back and change it the to the following.
Now my question, how should I update my table. The first thing that came into my mind was to delete the record that were already there and insert the new one's.
My real issue here is, assume user have choose the 3 items before but changed it two or one then how would i delete the those are not checked you know what I'm saying. Below is some code snippets that I've been trying.
$accidentRoadConditions = AccidentRoadConditions::findAccidentRoadConditions($acc_det_id);
$wc_array = [];
while ($roadConditions = $accidentRoadConditions ->fetch(PDO::FETCH_OBJ)) {
$wc_array[] = $roadConditions ->rc_id;
}
Above I'm selecting all the road conditions that is already stored in the database.
if (isset($_POST['rta_ad_rc'])) {
foreach ($_POST['rta_ad_rc'] as $rc_id) {
//AccidentRoadConditions::save(array(null, $ad_lsid, $rc_id));
// $tmprory = AccidentRoadConditions::findByADAndRCIds($acc_det_id, $rc_id);
// if(!$tmprory){
// AccidentRoadConditions::save(array(null, $acc_det_id, $rc_id));
// }
if(in_array($rc_id, $wc_array)){
$errors[] = "in array <br />";
unset($wc_array[0]);
}
}
}
So my question is how to update values in database according to what was checked by user and deleting those which were unchecked which were checked before. Getting bit complicated so simply how to update database according to above mention scenario.
Any Idea?
I think you need to do the following
Store the selected checks in an array
Check in the database if any of those are already saved or not
if yes, skipped them otherwise add them into an array
$old_rc_array = [];
$new_rc_array = [];
while ($roadConditions = $accidentRoadConditions->fetch(PDO::FETCH_OBJ)) {
$old_rc_array[] = $roadConditions->rc_id;
}
if (isset($_POST['rta_ad_rc'])) {
foreach ($_POST['rta_ad_rc'] as $rc_id) {
if(in_array($rc_id, $old_rc_array)){
unset($old_rc_array[array_search($rc_id, $old_rc_array)]);
}else{
$new_rc_array[] = $rc_id;
}
}
}
foreach ($old_rc_array as $rc_to_delete) {
AccidentRoadConditions::deleteByADIdAndRCId($hidden_acc_det_id, $rc_to_delete);
}
foreach ($new_rc_array as $rc_to_insert) {
AccidentRoadConditions::save(array(null, $hidden_acc_det_id, $rc_to_insert));
}
I think this is what you should do.
Create composite unique constraint on ad_id and rc_id
Delete all the rows not in the selected checkbox ids.
Try to insert all the rows but user INSERT IGNORE. This will insert the record if it does not exist or it will just ignore it. As you are using some framework see how you can do that.
If you can not then just wrap it using try/catch and ignore if the error is related to constraint violation.
This way You don't need to check if the values exist and also there will not be any unnecessary inserts.

Lots of 'If statement', or a redundant mysql query?

$url = mysql_real_escape_string($_POST['url']);
$shoutcast_url = mysql_real_escape_string($_POST['shoutcast_url']);
$site_name = mysql_real_escape_string($_POST['site_name']);
$site_subtitle = mysql_real_escape_string($_POST['site_subtitle']);
$email_suffix = mysql_real_escape_string($_POST['email_suffix']);
$logo_name = mysql_real_escape_string($_POST['logo_name']);
$twitter_username = mysql_real_escape_string($_POST['twitter_username']);
with all those options in a form, they are pre-filled in (by the database), however users can choose to change them, which updates the original database. Would it be better for me to update all the columns despite the chance that some of the rows have not been updated, or just do an if ($original_db_entry = $possible_new_entry) on each (which would be a query in itself)?
Thanks
I'd say it doesn't really matter either way - the size of the query you send to the server is hardly relevant here, and there is no "last updated" information for columns that would be updated unjustly, so...
By the way, what I like to do when working with such loads of data is create a temporary array.
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$$field = mysql_real_escape_string($_POST[$field]);
the only thing to be aware of here is that you have to be careful not to put variable names into $fields that would overwrite existing variables.
Update: Col. Shrapnel makes the correct and valid point that using variable variables is not a good practice. While I think it is perfectly acceptable to use variable variables within the scope of a function, it is indeed better not use them at all. The better way to sanitize all incoming fields and have them in a usable form would be:
$sanitized_data = array();
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$sanizited_data[$field] = mysql_real_escape_string($_POST[$field]);
this will leave you with an array you can work with:
$sanitized_data["url"] = ....
$sanitized_data["shoutcast_url"] = ....
Just run a single query that updates all columns:
UPDATE table SET col1='a', col2='b', col3='c' WHERE id = '5'
I would recommend that you execute the UPDATE with all column values. It'd be less costly than trying to confirm that the value is different than what's currently in the database. And that confirmation would be irrelevant anyway, because the values in the database could change instantly after you check them if someone else updates them.
If you issue an UPDATE against MySQL and the values are identical to values already in the database, the UPDATE will be a no-op. That is, MySQL reports zero rows affected.
MySQL knows not to do unnecessary work during an UPDATE.
If only one column changes, MySQL does need to do work. It only changes the columns that are different, but it still creates a new row version (assuming you're using InnoDB).
And of course there's some small amount of work necessary to actually send the UPDATE statement to the MySQL server so it can compare against the existing row. But typically this takes only hundredths of a millisecond on a modern server.
Yes, it's ok to update every field.
A simple function to produce SET statement:
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);
}
and usage:
$fields = explode(" ","name surname lastname address zip fax phone");
$query = "UPDATE $table SET ".dbSet($fields)." WHERE id=$id";

Categories