php database queries in foreach and optimization - php

I am creating a multilingual website and I want to display a different data for each country.
So i already had created script which determines the language and origin of the user and I need to load data from 3 databases on the website in foreach function.
I had 3 database
listFrom, listFromCountryCode, listFromLang
listFrom:
id, prefix, status
listFromCountryCode:
id, idList, countryCode, status,
listFromTranslate:
id, idList, name, langCode, status
currently, to get this data I need to do a loop for listFromCountryCode and listFrom to get prefix. I came up with some optimizations such as use INNER JOIN in query. I cant connect these database in one piece because prefix for other countries is the same. I haven't done this code yet because at the beginning I wanted to ask more experienced developers for advice on how to optimize it. I know that the use of a loop for database queries is bad but I have no idea for another solution.
Update
Already created script and time-tested so when in table is more elements (100) site loaded in 3s. Normal script without that script loaded in 0.46s. Anyone got any idea how to optimize this script?
public function checkCountryCodeList()
{
$sql = "SELECT COUNT(*) FROM listFromCountryCode WHERE countryCode = :code AND status = :status";
$array = array(':code' => $this->countryCode, ':status' => $this->status);
$result = $this->db->selectCount($sql, $array);
if($result > 0){
return true;
}else{
return false;
}
}
public function getCountryCodeList()
{
$sql = "SELECT idList
FROM listFromCountryCode
WHERE countryCode = :code";
$array = array(':code' => $this->countryCode);
$result = $this->db->select($sql, $array);
return $result;
}
public function getList()
{
if(!$this->checkCountryCodeList()){
$this->countryCode = DEFAULT_COUNTRYCODE;
}
$countryCodeList = $this->getCountryCodeList();
$data = array();
foreach($countryCodeList as $row){
$sql = "SELECT listFrom.prefix, listFromTranslation.name
FROM listFrom, listFromTranslation
WHERE listFrom.id = listFromTranslation.idList
AND listFrom.id = :id
And listFromTranslation.langCode = :code";
$array = array(
':id' => $row['idList'],
':code' => $this->langCode
);
$result = $this->db->select($sql, $array);
$data[] = ['name' => $result[0]['name'], 'prefix' => $result[0]['prefix']];
}
return $data;
}
Update
Some example data
listFrom
| id | prefix |status |
|--- | ------ |-------|
| 1 | btc |1 |
| 2 | psc |1 |
listFromCountryCode
| id | idList |countryCode |status |
|--- | ------ |------------|------ |
| 1 | 1 |de |1 |
| 2 | 2 |de |1 |
listFromTranslate
| id | idList| name |langCode |status |
|--- | ------| ----------- |---------|------ |
| 1 | 1 | bitcoin |en |1 |
| 2 | 2 | paysafecard |en |1 |

Related

Getting data from array to reference other table

Im trying to get data from one table based upon the date in a column from another table. I've tried using an inner join but I can't quite figure out how to make it do what I want. Below is an example. Basicly the numbers in the rules column will referance the rule_id in the infraction rules table. Then output the rule long name in readable text.
user_infractions table
+--------+-----------------+------------------+----------------+
|ban_id | name | username | rules |
+--------+-----------------+------------------+----------------+
| 2 | bob | Bob | 2,7, |
| 7 | dave | dave1 | 3,5, |
+--------+-----------------+------------------+----------------+
infraction_rules table
+--------+-----------------+------------------+----------------+
|rule_id | rule number | short_name | long_name |
+--------+-----------------+------------------+----------------+
| 2 | 1.2.2 | Rule 2 | Rule 2 Long Na |
| 7 | 1.2.7 | Rule 7 | Rule 7 Long Na |
+--------+-----------------+------------------+----------------+
Below is the code im using to try to achieve this
$string = $row['rules']; //data from table as a string
$strtrim = rtrim($string,","); //removed trailing comma from string
$violations = explode(",", $strtrim); // string to array conversion
foreach($violations as $violation) {
echo $violation;
$sql3 = "SELECT *
FROM user_infractions
INNER JOIN infraction_rules ON user_infractions.rules = infraction_rules.rule_id
WHERE user_infractions.rules = ?;";
$stmt3 = $conn->prepare($sql3);
//$stmt -> mysqli_stmt_prepare($stmt, $sql);
$stmt3->bind_param("s", $violation);
$stmt3->execute();
$result3 = $stmt3->get_result();
if ($result3->num_rows > 0) {
while ($row3 = $result3->fetch_assoc()) {
echo $row3['rule_long_desc'];
}
}
}

Generating JSON Query Result in Codeigniter

So i have database table named usermeta and have table structure like this :
-----------------------------------------------------------
| ummeta_id | user_id | meta_key | meta_value |
-----------------------------------------------------------
| 1 | 1 | fullname | John Doe |
| 2 | 1 | birthplace | New York |
| 3 | 1 | birthdate | 1990/01/01 |
| 4 | 1 | mobile | 0812-3456-7890 |
| 5 | 1 | email | john.doe#mail.com |
| 6 | 2 | fullname | Jon Wick |
| 7 | 2 | birthplace | Washington DC |
| 8 | 2 | birthdate | 1985/10/21 |
| 9 | 2 | mobile | 0890-1234-5678 |
| 10 | 2 | email | wickjohn#mail.com |
And i try to generate json data for all data from this database using Codeigniter (v 3.1.9) using Controller and Model.
This is my Model (model name: db_usermeta)
function userslist()
{
$query = $this->db->select('*')
->from('usermeta')
->get();
return $query->result();
}
This is my Controller
public function userlist()
{
header('Content-Type: application/json; charset=utf-8');
$query = $this->db_usermeta->userslist();
$json_data = array();
foreach ($query as $key)
{
$json_data[$key->meta_key] = $key->meta_value;
}
echo json_encode($json_data);
}
The result when i open using my browser to check the json data using web developer tool is only show last record, in this case only show data from user_id 2, like this:
{
"fullname":"John Wick",
"birthplace":"Washinton DC",
"birthdate":"1985/10/21",
"mobile":"0890-1234-5678",
"email":"wickjohn#mail.com"
}
What I want to achieve is to show all json data nested like this:
"data": [
{
"fullname":"John Doe",
"birthplace":"New York",
"birthdate":"1990/01/01",
"mobile":"0812-3456-7890",
"email":"john.doe#mail.com"
},
{
"fullname":"John Wick",
"birthplace":"Washinton DC",
"birthdate":"1985/10/21",
"mobile":"0890-1234-5678",
"email":"wickjohn#mail.com"
}
]
How can i achieve this? Did I make a mistake on my controller and model. I really appreciate your help.
your $key->meta_key is overwriting for every record. that's why only last record appeared. You don't actually need to loop through to get json data.
public function userlist()
{
header('Content-Type: application/json; charset=utf-8');
$query = $this->db_usermeta->userslist();
$json_data = array(array());
$user_id_map = array();
$index = 0;
foreach ($query as $key)
{
if(!isset($user_id_map[$key->user_id])){
$user_id_map[$key->user_id] = $index++;
}
$currentIndex = $user_id_map[$key->user_id];
$json_data[$currentIndex][$key->meta_key] = $key->meta_value;
}
echo json_encode($json_data);
}
just change your controller code to this and this will return json data.
Since the meta key fullname is same for both records, you need to change the key name to something unique
foreach ($query as $key)
{
$json_data[$key->meta_key] = $key->meta_value;
}
Change $json_data[$key->meta_key] to $json_data[$key->meta_key.$key->user_id]
or simply change it to $json_data[$key->ummeta_id]

Yii criteria selecting all rows

I am useing Yii framework to do a criteria selection for all rows that fit the criteria.
I am trying to take the ID of one table and search another tables codes that contain the prefix of the ID. (exp ID-code or 1-sdfa). Currently the code below is returning all of the rows as a result. Below are the details, any insight would help. Thank you.
[table 1]
tbl_School
---------------------------
| ID | Name |
---------------------------
| 1 | forist hills |
| 2 | Dhs |
---------------------------
[table 2]
tbl_ticket
------------------
| ID | code |
------------------
| 1 | 1-fd23s |
| 2 | 2-fdet2 |
| 3 | 1-4wscd |
| 4 | 2-oifjd |
| 5 | 1-zzds6 |
------------------
After runing the function on ID=1 I would like to see
------------------
| ID | code |
------------------
| 1 | 1-fd23s |
| 3 | 1-4wscd |
| 5 | 1-zzds6 |
------------------
Here is my code:
public static function get_tickets($ticket_ID){
$match = '';
$match = addcslashes($match, "$ticket_ID".'_%');
$q = new CDbCriteria( array(
'condition' => "code LIKE :match",
'params' => array(':match' => "$match%")
) );
$rows = Ticket::model()->findAll( $q );
return $rows;
}
PDO does escaping for you so you don't need to do the addcslashes yourself (I didn't even know that existed, always used addslashes :) )
Secondly, you end up selecting on [NUMBER]_%%, those are 3 wildcards.
As Ryan already changed in its comment, you might want to select on -% instead:
public static function get_tickets($ticket_ID){
$ticket_ID = intval($ticket_ID);
if (!$ticket_ID)
return null;
$q = new CDbCriteria( array(
'condition' => "code LIKE :match",
'params' => array(':match' => $ticket_ID . "-%")
) );
$rows = Ticket::model()->findAll( $q );
return $rows;
}
As you can see, I did do a numeric sanity check for the ticket number, just like being cautious.
Lastly: I hope you don't mind the suggestion, but isn't it simply possible adding the ticket number as a separate column? You are going to end up with perfectly avoidable performance problems if there are a lot of rows in this table. With a separate column that is an index you'd use a lot less cpu for the same result.

Fetching data from a table and storing in variables

I have website settings stored in a table like this:
+---------+-------------+
| id | value |
+---------+-------------+
| 1 | title |
| 2 | description |
| 3 | email |
| 4 | keywords |
+---------+-------------+
How can I select them and assign them to variables ($title, $desc, $email, $key)
// Get Website Infos
$result=$db->query("SELECT `value` FROM `settings`");
if($result->num_rows >= 1){
$row=$result->fetch_assoc();
$otitle=$row['value'];
$odescription=$row['value'];
$oemail=$row['value'];
$okeywords=$row['value'];
}
but it only get the first row 'title',any idea how to do it or better way to save settings.
UPDATE:
If you are reading this question now, don't use this structure to store your settings, use the one suggested by Yellow Bird in the answers.
You have to loop with your fetch_assoc() method :
$result = $db->query("SELECT `value` FROM `settings`");
if ($result->num_rows >= 1){
$data = array();
while ($row = $result->fetch_assoc()) {
$data[] = $row['value'];
}
}
var_dump($data);
As DanFromGermany noticed in comments, your db structure is probably not done the right way. You should have a design like this :
+---------+-------------+--------------+
| id | key | value |
+---------+-------------+--------------+
| 1 | title | title value |
| 2 | description | desc value |
| 3 | email | email value |
| 4 | keywords | keyw value |
+---------+-------------+--------------|
And then, your code would look like this :
$result = $db->query("SELECT key, value FROM `settings`");
if ($result->num_rows >= 1) {
$data = array();
while ($row = $result->fetch_assoc()) {
$data[$row['key']] = $row['value'];
}
}

mysql + php retrieve leaf children with path

I have a table that like this.
+-----------+-----------+-----------+-----------+-----------+-----------+
|id | parent_id | name | order | status | date_add |
+-----------+-----------+-----------+-----------+-----------+-----------+
|1 | 0 | shoes | 1 | 1 | 2011-04-02|
+-----------+-----------+-----------+-----------+-----------+-----------+
|2 | 1 | male | 2 | 1 | 2011-04-02|
+-----------+-----------+-----------+-----------+-----------+-----------+
|3 | 1 | female | 3 | 1 | 2011-04-02|
+-----------+-----------+-----------+-----------+-----------+-----------+
|4 | 3 | red shoes | 4 | 1 | 2011-04-02|
+-----------+-----------+-----------+-----------+-----------+-----------+
I want to select only the leaf children, with their path.
I want to come to the result as follows:
+------+-------------------------------------+
| 2 | shoes/male |
+------+-------------------------------------+
| 4 | shoes/female/red shoes |
+------+-------------------------------------+
if this does not only sql can also be php + sql
Please help me.
Very simple solution to print out id and path to all last child nodes using PHP as I am not aware of a way of doing this within MySQL. Hope this helps!
function getChildren($parent= "", $x = 0) {
$sql = "SELECT id, name FROM recurr WHERE parentId = $x";
$rs = mysql_query($sql);
//echo "Name: $parent has ". mysql_num_rows($rs)." children<br/>";
while ($obj = mysql_fetch_object($rs)) {
if (hasChildren($obj->id)) {
getChildren($parent."/".$obj->name, $obj->id);
} else {
echo $obj->id .", ".$parent."/".$obj->name."<br/>";
}
}
}
function hasChildren($x) {
$sql = "SELECT * FROM recurr WHERE parentId = $x";
$rs = mysql_query($sql);
if (mysql_num_rows($rs) > 0) {
return true;
} else {
return false;
}
}
To run just call:
getChildren();
I highly recommend implementing nested set model for hierarchical MySQL data. Here is the link for more info: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/. In the link, you will also find the answer to your question (under "The Adjacency List Model", "Finding all the Leaf Nodes" section)

Categories