How to seperate values from joined table result? - php

I have a simple joined table that looks like this.
NO CLASS NAME STATUS
1 1A JOHN 1
2 1A SARA 1
3 1A LYOD 1
4 1B JOHN 1
5 1B SHIN 1
I use textbox to display the CLASS and a TEXTAREA to display the NAME. The output of CLASS 1A should like this:
Class : 1A
Name : JOHN, SARA, LYOD
How to do it using the joined table only (not multiple query)?
THis is how I loop the result:
$query = $this->xxx->yyy($class_name); //JOINED RESULT
$data = array(
'titlepage' => APP_TITLEPAGE,
'record' => $query, //This is the result that is sent to the view
'complete' => 'true',
'loadmethod' => 'add',
'contentpage' => 'test_page/detail'
);
$this->load->view('shared/master_app', $data);

so your query array is something like this:
$query = [
['NO' => 1, 'CLASS' => '1A', 'NAME' => 'JOHN', 'STATUS' => '1'],
['NO' => 2, 'CLASS' => '1A', 'NAME' => 'SARA', 'STATUS' => '1'],
['NO' => 3, 'CLASS' => '1A', 'NAME' => 'LYOD', 'STATUS' => '1'],
['NO' => 4, 'CLASS' => '1B', 'NAME' => 'JOHN', 'STATUS' => '1'],
];
You may make a function that arrange it or group it
lets name it groupResults($query)
function groupResults($query) {
$result = [];
foreach($query as $queryItem) {
$result[$queryItem['CLASS']][] = $queryItem['NAME'];
}
return $result;
}
now result is looks like this:
$result = [
'1A' => ['JOHN', 'SARA', 'LYOD'],
'1B' => ['JOHN']
]
this is a snapshot of what I got:
so now you can use it like this
$query = $this->xxx->yyy($class_name); //JOINED RESULT
$data = array(
'titlepage' => APP_TITLEPAGE,
'record' => groupResults($query), //This is the result that is sent to the view
'complete' => 'true',
'loadmethod' => 'add',
'contentpage' => 'test_page/detail'
);
$this->load->view('shared/master_app', $data);
now in the view you may loop on this array as:
foreach($record as $class => $names) {
echo "<input type='text' value='" . $class . "'>";
echo "<textarea>" . implode(', ', $names) . "</textarea>";
}

If you want to add all name in same Class in one column then it can be possible by GROUP_CONCAT() mysql function.
adjust your query with GROUP_CONCAT. For an example see below
SELECT CLASS, GROUP_CONCAT(NAME)
FROM table_name
GROUP BY CLASS;
It will Output like this
1A JOHN,SARA,LYOD
2A JOHN,SHIN
You also can put custom separator between names using GROUP_COCAT separator
SELECT CLASS, GROUP_CONCAT(NAME SEPARATOR ' -- ')
FROM table_name
GROUP BY CLASS;
For reference MySql GROUP_CONCAT()

Related

Formatting Excel Laravel with array data

I'm trying to write an excel from a laravel controller where i have all the data in an array, and i managed to write it, but i have to format it now, this is the array that i have:
[2020-12-30 13:22:05] local.DEBUG: array (
0 =>
array (
0 => '1',
1 => '2',
),
1 =>
array (
0 => 'Test Name 1',
1 => 'Test Name 2',
),
2 =>
array (
0 => 'user',
1 => 'user2',
),
3 =>
array (
0 => '1',
1 => '2',
),
)
This is the way i'm creating the Excel:
Excel::create('Filename', function($excel) use ($budgets) {
$excel->sheet('Sheetname', function($sheet) use ($budgets) { //$budgets is the array i'm printing on Log
$sheet->fromArray($budgets);
});
})->export('xls');
And this is the way that my excel is printing it:
1
2
Test Name 1
Test Name 2
user1
user2
1
2
And the way i want to print it is:
Code
Name
User
Number
1
Test Name 1
user1
1
2
Test Name 2
user2
2
But i don't know how to achieve this. Can anyone help me with this?
//edits//
I added some code to re estructure the array, now i have this:
$users = ['Code', 'Name', 'User', 'Number'];
for ($i=0; $i<count($code); $i++){
array_push($users, array($code[$i], $name[$i], $user[$i], $number[$i]));
}
Log::debug($users);
And this is the Log:
[2020-12-30 15:17:40] local.DEBUG: array (
0 => 'Code',
1 => 'Name',
2 => 'User',
3 => 'Number',
4 =>
array (
0 => '1',
1 => 'Test Name 1',
2 => 'user1',
3 => '1',
),
5 =>
array (
0 => '2',
1 => 'Test Name 2',
2 => 'user2',
3 => '2',
),
)
But i'm getting this error:
[message] => Row `Code` must be array.
[class] => PHPExcel_Exception
You will could re-structure your array.
To get the print you want array should look like:
$budget = [
['Code', 'Name', 'User', 'Number'],
[1, 'Test Name 1', 'user1', 1],
...
];
Ok, so, i managed to re-structure the array and getting the Excel the way i wanted doing this:
public function generateExcel(Request $request)
{
$code = $request->input('code');
$name = $request->input('name');
$user = $request->input('user');
$number = $request->input('number');
$users = array();
array_push($users, array('Code', 'Name', 'User', 'Number'));
for ($i=0; $i<count($code); $i++){
array_push($users, array($code[$i], $name[$i], $user[$i], $number[$i]));
}
Excel::create('Filename', function($excel) use ($users) {
$excel->sheet('Sheetname', function($sheet) use ($users) {
$sheet->fromArray($users);
});
})->export('xls');
return true;

Keep array rows where a column value is found in a second flat array

** I have edited this to show how I got my code to work using array_search
I have an array, $arr1 with 5 columns as such:
key id name style age whim
0 14 bob big 33 no
1 72 jill big 22 yes
2 39 sue yes 111 yes
3 994 lucy small 23 no
4 15 sis med 24 no
5 16 maj med 87 yes
6 879 Ike larg 56 no
7 286 Jed big 23 yes
This array is in a cache, not a database.
I then have a second array with a list of id values -
$arr2 = array(0=>14, 1=>72, 2=>8790)
How do I filter $arr1 so it returns only the rows with the id values in $arr2?
I got my code to work as follows:
$arr1 = new CachedStuff(); // get cache
$resultingArray = []; // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);
This gives me two outputs: $resultingArray & $resultingArrayIDs both of which represent the intersection of the $arr1 and $arr2.
This whole task can be accomplished with just one slick, native function call -- array_uintersect().
Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declered, then fallback to the parameter's value.
Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.
Code: (Demo)
var_export(
array_uintersect(
$arr1,
$arr2,
fn($a, $b) =>
($a['id'] ?? $a)
<=>
($b['id'] ?? $b)
)
);
Something like this should do it, provided I've understood your question and data structure correctly:
$dataArray = [
[ 'key' => 0, 'id' => 14 , 'name' => 'bob' , 'style' => 'big' , 'age' => 33 , 'whim' => 'no' ],
[ 'key' => 1, 'id' => 72 , 'name' => 'jill' , 'style' => 'big' , 'age' => 22 , 'whim' => 'yes' ],
[ 'key' => 2, 'id' => 39 , 'name' => 'sue' , 'style' => 'yes' , 'age' => 111 , 'whim' => 'yes' ],
[ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23 , 'whim' => 'no' ],
[ 'key' => 4, 'id' => 15 , 'name' => 'sis' , 'style' => 'med' , 'age' => 24 , 'whim' => 'no' ],
[ 'key' => 5, 'id' => 16 , 'name' => 'maj' , 'style' => 'med' , 'age' => 87 , 'whim' => 'yes' ],
[ 'key' => 6, 'id' => 879 , 'name' => 'Ike' , 'style' => 'larg' , 'age' => 56 , 'whim' => 'no' ],
[ 'key' => 7, 'id' => 286 , 'name' => 'Jed' , 'style' => 'big' , 'age' => 23 , 'whim' => 'yes' ]
];
$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
return in_array( $row[ 'id' ], $filterArray );
} );
View this example on eval.in
However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.
One way is with foreach loop with array_search()
$result = [];
foreach ($arr1 as $value) { // Loop thru $arr1
if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
$result[] = $value; // Push to result if true
}
}
// print result
print_r($result);
As #DecentDabbler mentioned - if the data is coming out of a database, using an IN on your WHERE will allow you to retrieve only the relevant data.
Another way to filter is to use array functions
array_column extracts the value of the id column into an array
array_intersect returns the elements which are in both $arr1['id'] and $arr2
array_flip flips the resulting array such that the indices into $arr1 indicate the elements in both $arr1 and $arr2
$arr1 = [ [ 'id' => 14, 'name' => 'bob'],
['id' => 72, 'name' => 'jill'],
['id' => 39, 'name' => 'sue'],
['id' => 994, 'name' => 'lucy'],
['id' => 879, 'name'=> 'large']];
$arr2 = [ 14,72,879 ];
$intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
foreach ($intersection as $i) {
var_dump($arr1[$i]);;
}

loop on foreach with distinct ?

I have a probleme with a array.
In my array that has 15,000 rows, I have columns with associated names and values ​​(sku).
I need to show all the names and make a separate on it if the sku is equal or not to the sku that is present on my product page
Exemple : array = [ 'code' => 'name1' ,
'sku' => '123456',
'code' => 'name1',
'sku' => '456789',
'code' => 'name2',
'sku' => '4565999']
etc ..........
if sku equals sku or not in my page product, i want to show the code with distinct on this .
First you need an array of arrays structure like this:
$arr = [
[ 'code' => 'name1', 'sku' => '123456' ],
[ 'code' => 'name2', 'sku' => '456789' ],
[ 'code' => 'name3', 'sku' => '4565999' ],
.
.
.
Then you can filter your array like this:
$existing_items_on_array = array_filter($arr,
function($item) use ($existing_items_on_page){
return array_search($item["sku"], $existing_items_on_page) !== false;
});
Or better (you still need to structure an array like on first solution):
I assume your SKU's are unique. Why not make them array keys?
$item_codes = [];
foreach($arr as $item){
$item_codes[$item["sku"]] = $item["code"];
}
then you would be accessing any element's code like this:
echo $item_codes[$product["sku"]]

How to use pagination with JOINs in Zend Framework 2?

In an application I implemented a Mapper to retrieve data from the database and objects from the ResultSet. In order to get all the data I have to JOIN multiple tables. Then I get a huge array structured like this:
[
0 => [
main_id => 1,
main_title => 'lorem',
main_desc => 'ipsum',
foo_id => '12',
foo_name => 'qwer',
bar_id => '56',
bar_name => 'asdf'
],
1 => [
main_id => 1,
main_title => 'lorem',
main_desc => 'ipsum',
foo_id => '12',
foo_name => 'qwer',
bar_id => '67',
bar_name => 'hjkl'
],
2 => [
main_id => 1,
main_title => 'lorem',
main_desc => 'ipsum',
foo_id => '23',
foo_name => 'uiop',
bar_id => '67',
bar_name => 'hjkl'
],
...
10 => [
main_id => 1,
main_title => 'lorem',
main_desc => 'ipsum',
foo_id => '23',
foo_name => 'uiop',
bar_id => '91',
bar_name => 'cvbn'
],
11 => [
main_id => 2,
main_title => 'dolor',
main_desc => 'sit',
foo_id => '78',
foo_name => 'fghj',
bar_id => '89',
bar_name => 'vbnm'
],
...
12 => [
main_id => 3,
foo_id => '135',
bar_id => '246',
...
],
13 => [
main_id => 3,
foo_id => '135',
bar_id => '468',
...
],
14 => [
main_id => 3,
foo_id => '357',
bar_id => '680',
...
],
...
1000 => [
...
]
]
Then I iterate over the array, build objects (Main, Foo, Bar etc.), and combine them, e.g.
$newMain = $myMainHydrator->hydrate($results[0]);
$newFoo = $myFooHydrator->hydrate($results[0]);
$newBar = $myBarHydrator->hydrate($results[0]);
$newFoo->setBar($newBar);
$newMain->setFoo($newFoo);
$resultObjects[] = $newMain;
Now I built in a Paginator and got following issue: The Paginator sets a LIMIT, e.g. 10, and retrieves then only 10 rows, while I need for every object more than one result row (currently even 12 rows).
I cannot believe, that the Paginator cannot handle JOINs, so there must be a way to get it working. How to use the Paginator for complex SELECTs with JOINs?
The issue can be solved by replacing of the LIMIT clause by an IN in the Paginator Adapter's getItems(...).
namespace Foo\Paginator\Adapter;
use Zend\Db\Sql\Select;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;
class FooPaginatorAdapter extends DbSelect
{
public function count()
{
$select = new Select();
$select->from('foo')->columns([self::ROW_COUNT_COLUMN_NAME => new Expression('COUNT(*)')]);
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$row = $result->current();
$this->rowCount = $row[self::ROW_COUNT_COLUMN_NAME];
return $this->rowCount;
}
public function getItems($offset, $itemCountPerPage)
{
$select = clone $this->select;
// replaced
// $select->offset($offset);
// $select->limit($itemCountPerPage);
// by this
$relevantIds = $this->getRelevantIds($offset, $itemCountPerPage);
$select->where->in('foo.id', $relevantIds);
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$resultSet = clone $this->resultSetPrototype;
$resultSet->initialize($result);
return iterator_to_array($resultSet);
}
protected function getRelevantIds($offset, $itemCountPerPage)
{
$sql = new Sql($this->sql->getAdapter());
$select = $sql->select('foo');
$select->columns(['id']);
$select->offset($offset);
$select->limit($itemCountPerPage);
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$resultArray = iterator_to_array($result);
$relevantIds = array_column($resultArray, 'id');
return $relevantIds;
}
}
As you see in this case the IDs first have to be retrieved with a separate database request. But anyway -- it works. If you know a better solution, please feel free to post it.

passing query fields n rows to array

I'm trying to fetch all rows to an array variable
array that i want is like this
$data1 = array('fields'=>array(
array(
'id' => 1,
'nama_file' => "sunset.jpg",
'judul' => "Sunset",
'isi' => "Matahari terbenam indah sekali",
),
array(
'id' => 2,
'nama_file' => "water_lilies.jpg",
'judul' => "Bunga Lilly",
'isi' => "Bunga lilly air sangat indah",
),)
And I've done this:
$q = $this->db->query('select id, nama_file, judul, isi from tfoto where dihapus ="T" ');
$data1=array('fields');
foreach($q->result() as $row) {
$data1['fields']=array('id'=>$row->id,'nama_file'=>$row->nama_file,'judul'=>$row->judul, 'isi'=>$row->isi);
}
test output:
<?php
foreach($fields as $field){
echo $field['nama_file'];
.
.
.
};?>
and I got Message: Illegal string offset 'nama_file';'judul'; etc.
I am a newbie to MySQL/PHP, so forgive me if this is a very basic question. I tried looking all over but I could not find an answer to it.
This line:
$data1['fields']=array('id'=>$row->id,'nama_file'=>$row->nama_file,'judul'=>$row->judul, 'isi'=>$row->isi);
Should be:
$data1['fields'][] = array('id'=>$row->id,'nama_file'=>$row->nama_file,'judul'=>$row->judul, 'isi'=>$row->isi);
Because you have to append new arrays to $data1 and not replacing it.

Categories