I need help.
I have data with commas (,). And I want to convert it to array or json.
But when looping through it, the data in the first and last elements is duplicated.
Data from database on column additional. with NULL as default.
example:
+----+------------+
| id | addtional |
+----+------------+
| 1 | ada |
| 2 | NULL |
| 3 | kursi,meja |
| 4 | NULL |
+----+------------+
then call for looping
if( $p->additional !== NULL ) {
$gmb = explode(',', $p->additional);
$gmbbb = array();
foreach ($gmb as $gbr) {
$gmbbb[] = $gbr;
}
$keterangan['i'] = $gmbbb;
}
And the final result from $keterangan is:
Array
(
[i] => Array
(
[0] => ada
)
)
Array
(
[i] => Array
(
[0] => ada
)
)
Array
(
[i] => Array
(
[0] => kursi
[1] => meja
)
)
Array
(
[i] => Array
(
[0] => kursi
[1] => meja
)
)
How to stop duplicate if it's NULL, I need data from additional when it's NOT NULL.
This is different approach for you.Hope this will help you.But i dont know your table name and all.Make the sql query like below:
mysql>SELECT addtional FROM table_name WHERE addtional IS NOT NULL;
here is my table and I need to make a search function using codeigniter that will display the a list of items that contains my keywords order by most number of matched keywords and latest date added.
Ex. the two submitted keyword are yes, test
messages table
id | title | msg |date
---+-----------+-------------------+--------
1 | test1 | yes | 2016-06-01 // 2 match keywords
2 | yes1 | no | 2016-06-02 // 1 match keywords
3 | test2 | no | 2016-06-03 // 1 match keywords
4 | yes2 | yes yes yes | 2016-06-04 // 4 match keywords
5 | yesyes3 | yes yes yes yes | 2016-06-05 // 6 match keywords
now for expected output it will display:
array (
[0] => array (
[id] => 5
[title] => yesyes3
[msg] => yes yes yes yes
[date] => 2016-06-05
[match] => 6
)
[1] => array (
[id] => 4
[title] => yes2
[msg] => yes yes yes
[date] => 2016-06-04
[match] => 4
)
[2] => array (
[id] => 1
[title] => test1
[msg] => yes
[date] => 2016-06-01
[match] => 2
)
[3] => array (
[id] => 3
[title] => test2
[msg] => no
[date] => 2016-06-03
[match] => 1
)
[4] => array (
[id] => 2
[title] => yes1
[msg] => no
[date] => 2016-06-02
[match] => 1
)
)
Currently here are my current code and i'm not sure with these on how to make this search works
$match = array('yes','test');
$array = array('m.title' => $match, 'm.msg' => $match);
$this->db->select('m.*');
$this->db->from('messages m');
$this->db->like($array);
$this->db->order_by('m.date', 'DESC');
$query = $this->db->get();
Is there any php codeigniter code for this?
Thanks!
You will need to create a ORDER BY clause using search terms.
So the Full code
EDITED
$match = array('yes','test');
//$array = array('m.title' => $match, 'm.msg' => $match);//you do not need this
$orderbyString = "";
$likestr = "";
//first prepare an ORDER BY statement and like statement
foreach($match AS $value)
{
$orderbyString .= "IF(m.title LIKE '%".$value."%' OR m.msg LIKE '%".$value."%',1,0)+";
$likestr .= "m.title LIKE '%".$value."%' OR m.msg LIKE '%".$value."%' OR ";
}
$orderbyString = substr($orderbyString, 0, -1);
$likestr = substr($likestr, 0, -4);
$this->db->select('m.*, ('.$orderbyString.') as count_match');
$this->db->from('messages m');
$this->db->where($likestr." ORDER BY ".$orderbyString." DESC");
//$this->db->order_by($orderbyString, 'DESC');//removed this line
$query = $this->db->get();
$results = $query->result_array();//contains the desired result
Using the query builder to try and select rows where a value in the HSTORE key $type is present.
My Where Statement:
->where("meta_data_fields->'$type'", 'like', '%'.$query.'%')
Not sure what I'm doing wrong. I get this error:
Undefined column: 7 ERROR: column "meta_data_fields->'Entity::hstore'" does not exist
Any ideas?
to get all records in table that have HSTORE
Model::where("meta_data_fields", 'like', '%'.$query.'%')->get();
This should do normally do the trick. In your case, data in meta_data_fields is a json string. if the search is performed on all rows in the table, will select all. So here is What I did,
I created a queryScope in the model
1 - fetch all data
2 - extract meta_data_field and decode it
3 - loop through meta_data_field
4 - select only that match the criteria and build the array
here is a table
+----+-------------+------------------------------------+-----------+
| id | name | desc | vendor_id |
+----+-------------+------------------------------------+-----------+
| 1 | apples | {"type":"fruit","origin":"mexico"} | 1 |
| 2 | oranges | {"type":"fruit","origin":"peru"} | 1 |
| 3 | Peaches | {"type":"fruit","origin":"mexico"} | 2 |
| 4 | Cherries | {"type":"fruit","origin":"us"} | 1 |
| 5 | banans | {"type":"fruit","origin":"brazil"} | NULL |
| 6 | Water Melon | {"type":"fruit","origin":"mexico"} | 1 |
+----+-------------+------------------------------------+-----------+
public function scopeItems($name ="mexico"){
$items = array();
$data = Self::get();
$meta_fields = json_decode($data -> pluck('desc') ,true);
foreach ($meta_fields as $key => $value) {
if (isset($value['origin']) && $value['origin'] == $name ){
$items[$key] = $data[$key] -> toArray();
}
}
return $items;
}
// output
Array
(
[0] => Array
(
[id] => 1
[name] => apples
[desc] => Array
(
[type] => fruit
[origin] => mexico
)
[vendor_id] => 1
)
[2] => Array
(
[id] => 3
[name] => Peaches
[desc] => Array
(
[type] => fruit
[origin] => mexico
)
[vendor_id] => 2
)
[5] => Array
(
[id] => 6
[name] => Water Melon
[desc] => Array
(
[type] => fruit
[origin] => mexico
)
[vendor_id] => 1
)
)
Hope this works for you this time.
So here's what worked in my situation with Laravel.
$result = \DB::select(\DB::raw("SELECT hstore_fields, id from table where lower(hstore_fields->'$type') like lower('%$query%')"));
given a very simple table structure thus:
mysql> describe songpart;
+----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | MUL | NULL | auto_increment |
| partName | text | NO | | NULL | |
+----------+---------+------+-----+---------+----------------+
which results in an array like this in php (when queried)
Array ( [0] => Array ( [id] => 1 [0] => 1 [partName] => Lead Guitar [1] => Lead Guitar )
[1] => Array ( [id] => 2 [0] => 2 [partName] => Bass Guitar [1] => Bass Guitar )
[2] => Array ( [id] => 3 [0] => 3 [partName] => Drums [1] => Drums )
[3] => Array ( [id] => 4 [0] => 4 [partName] => Keyboard [1] => Keyboard ) )
Am I missing some simple trick to turn this into a simple array with id as the key like so:
Array ( [1] => Lead Guitar
[2] => Bass Guitar
[3] => Drums
[4] => Keyboard )
or is it possible to get PDO to deliver an array like this?
TiA
You can simply use the PDO::FETCH_KEY_PAIR is you have only 2 columns in your result.
You can also use the PDO::FETCH_GROUP and PDO::FETCH_ASSOC together if you have more. Example :
$result = $db->query('select * from channels')->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
This will yield an array indexed with the first column containing at each index an array of the result for this key. You can fix this by using array_map('reset', $result) to get your goal.
Example :
$result = array_map('reset', $db->query('select * from channels')->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC));
Try this:
$records = $pdo->query('SELECT id, partName FROM myTable');
$records->setFetchMode(PDO::FETCH_KEY_PAIR);
print_r($records->fetchAll());
For that you need to set only your desired fields in iteration.
$part_name = [];
$records = $pdo->query('SELECT * FROM your_table');
foreach ($records as $row) {
$part_name[$row['id']] = $row['partName'];
}
I have just made the update/add/delete part for the "Closure table" way of organizing query hierarchical data that are shown on page 70 in this slideshare: http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back
My database looks like this:
Table Categories:
ID Name
1 Top value
2 Sub value1
Table CategoryTree:
child parent level
1 1 0
2 2 0
2 1 1
However, I have a bit of an issue getting the full tree back as an multidimensional array from a single query.
Here's what I would like to get back:
array (
'topvalue' = array (
'Subvalue',
'Subvalue2',
'Subvalue3)
);
);
Update:
Found this link, but I still have a hard time to convert it into an array:
http://karwin.blogspot.com/2010/03/rendering-trees-with-closure-tables.html
Update2 :
I was able to add depths to each of the categories now, if that can be of any help.
Okay, I've written PHP classes that extend the Zend Framework DB table, row, and rowset classes. I've been developing this anyway because I'm speaking at PHP Tek-X in a couple of weeks about hierarchical data models.
I don't want to post all my code to Stack Overflow because they implicitly get licensed under Creative Commons if I do that. update: I committed my code to the Zend Framework extras incubator and my presentation is Models for Hierarchical Data with SQL and PHP at slideshare.
I'll describe the solution in pseudocode. I'm using zoological taxonomy as test data, downloaded from ITIS.gov. The table is longnames:
CREATE TABLE `longnames` (
`tsn` int(11) NOT NULL,
`completename` varchar(164) NOT NULL,
PRIMARY KEY (`tsn`),
KEY `tsn` (`tsn`,`completename`)
)
I've created a closure table for the paths in the hierarchy of taxonomy:
CREATE TABLE `closure` (
`a` int(11) NOT NULL DEFAULT '0', -- ancestor
`d` int(11) NOT NULL DEFAULT '0', -- descendant
`l` tinyint(3) unsigned NOT NULL, -- levels between a and d
PRIMARY KEY (`a`,`d`),
CONSTRAINT `closure_ibfk_1` FOREIGN KEY (`a`) REFERENCES `longnames` (`tsn`),
CONSTRAINT `closure_ibfk_2` FOREIGN KEY (`d`) REFERENCES `longnames` (`tsn`)
)
Given the primary key of one node, you can get all its descendants this way:
SELECT d.*, p.a AS `_parent`
FROM longnames AS a
JOIN closure AS c ON (c.a = a.tsn)
JOIN longnames AS d ON (c.d = d.tsn)
LEFT OUTER JOIN closure AS p ON (p.d = d.tsn AND p.l = 1)
WHERE a.tsn = ? AND c.l <= ?
ORDER BY c.l;
The join to closure AS p is to include each node's parent id.
The query makes pretty good use of indexes:
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-----------------------------+
| 1 | SIMPLE | a | const | PRIMARY,tsn | PRIMARY | 4 | const | 1 | Using index; Using filesort |
| 1 | SIMPLE | c | ref | PRIMARY,d | PRIMARY | 4 | const | 5346 | Using where |
| 1 | SIMPLE | d | eq_ref | PRIMARY,tsn | PRIMARY | 4 | itis.c.d | 1 | |
| 1 | SIMPLE | p | ref | d | d | 4 | itis.c.d | 3 | |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-----------------------------+
And given that I have 490,032 rows in longnames and 4,299,883 rows in closure, it runs in pretty good time:
+--------------------+----------+
| Status | Duration |
+--------------------+----------+
| starting | 0.000257 |
| Opening tables | 0.000028 |
| System lock | 0.000009 |
| Table lock | 0.000013 |
| init | 0.000048 |
| optimizing | 0.000032 |
| statistics | 0.000142 |
| preparing | 0.000048 |
| executing | 0.000008 |
| Sorting result | 0.034102 |
| Sending data | 0.001300 |
| end | 0.000018 |
| query end | 0.000005 |
| freeing items | 0.012191 |
| logging slow query | 0.000008 |
| cleaning up | 0.000007 |
+--------------------+----------+
Now I post-process the result of the SQL query above, sorting the rows into subsets according to the hierarchy (pseudocode):
while ($rowData = fetch()) {
$row = new RowObject($rowData);
$nodes[$row["tsn"]] = $row;
if (array_key_exists($row["_parent"], $nodes)) {
$nodes[$row["_parent"]]->addChildRow($row);
} else {
$top = $row;
}
}
return $top;
I also define classes for Rows and Rowsets. A Rowset is basically an array of rows. A Row contains an associative array of row data, and also contains a Rowset for its children. The children Rowset for a leaf node is empty.
Rows and Rowsets also define methods called toArrayDeep() which dump their data content recursively as a plain array.
Then I can use the whole system together like this:
// Get an instance of the taxonomy table data gateway
$tax = new Taxonomy();
// query tree starting at Rodentia (id 180130), to a depth of 2
$tree = $tax->fetchTree(180130, 2);
// dump out the array
var_export($tree->toArrayDeep());
The output is as follows:
array (
'tsn' => '180130',
'completename' => 'Rodentia',
'_parent' => '179925',
'_children' =>
array (
0 =>
array (
'tsn' => '584569',
'completename' => 'Hystricognatha',
'_parent' => '180130',
'_children' =>
array (
0 =>
array (
'tsn' => '552299',
'completename' => 'Hystricognathi',
'_parent' => '584569',
),
),
),
1 =>
array (
'tsn' => '180134',
'completename' => 'Sciuromorpha',
'_parent' => '180130',
'_children' =>
array (
0 =>
array (
'tsn' => '180210',
'completename' => 'Castoridae',
'_parent' => '180134',
),
1 =>
array (
'tsn' => '180135',
'completename' => 'Sciuridae',
'_parent' => '180134',
),
2 =>
array (
'tsn' => '180131',
'completename' => 'Aplodontiidae',
'_parent' => '180134',
),
),
),
2 =>
array (
'tsn' => '573166',
'completename' => 'Anomaluromorpha',
'_parent' => '180130',
'_children' =>
array (
0 =>
array (
'tsn' => '573168',
'completename' => 'Anomaluridae',
'_parent' => '573166',
),
1 =>
array (
'tsn' => '573169',
'completename' => 'Pedetidae',
'_parent' => '573166',
),
),
),
3 =>
array (
'tsn' => '180273',
'completename' => 'Myomorpha',
'_parent' => '180130',
'_children' =>
array (
0 =>
array (
'tsn' => '180399',
'completename' => 'Dipodidae',
'_parent' => '180273',
),
1 =>
array (
'tsn' => '180360',
'completename' => 'Muridae',
'_parent' => '180273',
),
2 =>
array (
'tsn' => '180231',
'completename' => 'Heteromyidae',
'_parent' => '180273',
),
3 =>
array (
'tsn' => '180213',
'completename' => 'Geomyidae',
'_parent' => '180273',
),
4 =>
array (
'tsn' => '584940',
'completename' => 'Myoxidae',
'_parent' => '180273',
),
),
),
4 =>
array (
'tsn' => '573167',
'completename' => 'Sciuravida',
'_parent' => '180130',
'_children' =>
array (
0 =>
array (
'tsn' => '573170',
'completename' => 'Ctenodactylidae',
'_parent' => '573167',
),
),
),
),
)
Re your comment about calculating depth -- or really length of each path.
Assuming you've just inserted a new node to your table that holds the actual nodes (longnames in the example above), the id of the new node is returned by LAST_INSERT_ID() in MySQL or else you can get it somehow.
INSERT INTO Closure (a, d, l)
SELECT a, LAST_INSERT_ID(), l+1 FROM Closure
WHERE d = 5 -- the intended parent of your new node
UNION ALL SELECT LAST_INSERT_ID(), LAST_INSERT_ID(), 0;
Proposed Solution
This following example gives a little more than you ask for, but it's a really nice way of doing it and still demonstrates where the information comes from at each stage.
It uses the following table structure:
+--------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| parent | int(10) unsigned | NO | | NULL | |
| name | varchar(45) | NO | | NULL | |
+--------+------------------+------+-----+---------+----------------+
Here it is:
<?php
// Connect to the database
mysql_connect('localhost', 'root', '');
mysql_select_db('test');
echo '<pre>';
$categories = Category::getTopCategories();
print_r($categories);
echo '</pre>';
class Category
{
/**
* The information stored in the database for each category
*/
public $id;
public $parent;
public $name;
// The child categories
public $children;
public function __construct()
{
// Get the child categories when we get this category
$this->getChildCategories();
}
/**
* Get the child categories
* #return array
*/
public function getChildCategories()
{
if ($this->children) {
return $this->children;
}
return $this->children = self::getCategories("parent = {$this->id}");
}
////////////////////////////////////////////////////////////////////////////
/**
* The top-level categories (i.e. no parent)
* #return array
*/
public static function getTopCategories()
{
return self::getCategories('parent = 0');
}
/**
* Get categories from the database.
* #param string $where Conditions for the returned rows to meet
* #return array
*/
public static function getCategories($where = '')
{
if ($where) $where = " WHERE $where";
$result = mysql_query("SELECT * FROM categories$where");
$categories = array();
while ($category = mysql_fetch_object($result, 'Category'))
$categories[] = $category;
mysql_free_result($result);
return $categories;
}
}
Test Case
In my database I have the following rows:
+----+--------+-----------------+
| id | parent | name |
+----+--------+-----------------+
| 1 | 0 | First Top |
| 2 | 0 | Second Top |
| 3 | 0 | Third Top |
| 4 | 1 | First Child |
| 5 | 1 | Second Child |
| 6 | 2 | Third Child |
| 7 | 2 | Fourth Child |
| 8 | 4 | First Subchild |
| 9 | 4 | Second Subchild |
+----+--------+-----------------+
And thus the script outputs the following (lengthy) information:
Array
(
[0] => Category Object
(
[id] => 1
[parent] => 0
[name] => First Top
[children] => Array
(
[0] => Category Object
(
[id] => 4
[parent] => 1
[name] => First Child
[children] => Array
(
[0] => Category Object
(
[id] => 8
[parent] => 4
[name] => First Subchild
[children] => Array
(
)
)
[1] => Category Object
(
[id] => 9
[parent] => 4
[name] => Second Subchild
[children] => Array
(
)
)
)
)
[1] => Category Object
(
[id] => 5
[parent] => 1
[name] => Second Child
[children] => Array
(
)
)
)
)
[1] => Category Object
(
[id] => 2
[parent] => 0
[name] => Second Top
[children] => Array
(
[0] => Category Object
(
[id] => 6
[parent] => 2
[name] => Third Child
[children] => Array
(
)
)
[1] => Category Object
(
[id] => 7
[parent] => 2
[name] => Fourth Child
[children] => Array
(
)
)
)
)
[2] => Category Object
(
[id] => 3
[parent] => 0
[name] => Third Top
[children] => Array
(
)
)
)
Example Usage
I'd suggest creating some kind of recursive function if you're going to create menus from the data:
function outputCategories($categories, $startingLevel = 0)
{
$indent = str_repeat(" ", $startingLevel);
foreach ($categories as $category)
{
echo "$indent{$category->name}\n";
if (count($category->children) > 0)
outputCategories($category->children, $startingLevel+1);
}
}
$categories = Category::getTopCategories();
outputCategories($categories);
which would output the following:
First Top
First Child
First Subchild
Second Subchild
Second Child
Second Top
Third Child
Fourth Child
Third Top
Enjoy
I loved the answer from icio, but I prefer to have arrays of arrays, rather than arrays of objects. Here is his script modified to work without making objects:
<?php
require_once('mysql.php');
echo '<pre>';
$categories = Taxonomy::getTopCategories();
print_r($categories);
echo '</pre>';
class Taxonomy
{
public static function getTopCategories()
{
return self::getCategories('parent_taxonomycode_id = 0');
}
public static function getCategories($where = '')
{
if ($where) $where = " WHERE $where";
$result = mysql_query("SELECT * FROM taxonomycode $where");
$categories = array();
// while ($category = mysql_fetch_object($result, 'Category'))
while ($category = mysql_fetch_array($result)){
$my_id = $category['id'];
$category['children'] = Taxonomy::getCategories("parent_taxonomycode_id = $my_id");
$categories[] = $category;
}
mysql_free_result($result);
return $categories;
}
}
I think it fair to note that both my answer, and icios do not address your question directly. They both rely on having a parent id link in the main table, and make no use of the closure table. However, recursively querying the database is definitely the way to do, but instead of recursively passing the parent id, you have to pass in the parent id AND the level of the depth (which should increase by one on each recursion) so that the queries at each level can use parent + depth to get the direct parent information from the closure table rather than having it in the main table.
HTH,
-FT
When you want the output as a unordered list you can change the outputCategories method as follows (based on ftrotters arrays in arrays):
public function outputCategories($categories, $startingLevel = 0)
{
echo "<ul>\n";
foreach ($categories as $key => $category)
{
if (count($category['children']) > 0)
{
echo "<li>{$category['name']}\n";
$this->outputCategories($category['children'], $startingLevel+1);
echo "</li>\n";
}
else
{
echo "<li>{$category['name']}</li>\n";
}
}
echo "</ul>\n";
}
Sorry but I don't think you can't get a multi-dimensional array out of your (or any) database query.