Codeigniter retrieve top 5 most occurring rows in column - php

I currently am using codeigniter 3 to build a website. I have been able to build a full gallery and cart system using the database and active record. As well as a backend. I am currently now working the charts.js to build a pie graph in the backend of the 5 top sellers on the site. As well I will be making a graph for items sold by hour using the line graph. I can make the charts appear with dummy data no problem, however I am running into an issue of trying to retrieve the right data from the DB. It appears the query is going to be quite complex.
My mysql table is named order_items. And in order items there is a column qty and a column product_type. Both return integers. What I need is to find which five items have sold the most quantity. Eventually I will need to add the data to my charts.js setup as follows. Anyone with advanced experience with codeigniter active record?
var pieData = [{
value : 300,
color : "#F7464A",
highlight : "#FF5A5E",
label : "Product 1"
}, {
value : 125,
color : "#46BFBD",
highlight : "#5AD3D1",
label : "Product 2"
}, {
value : 100,
color : "#FDB45C",
highlight : "#FFC870",
label : "Product 3"
}, {
value : 40,
color : "#949FB1",
highlight : "#A8B3C5",
label : "Product 4"
}, {
value : 20,
color : "#4D5360",
highlight : "#616774",
label : "Product 5"
}];

I think you should try this script,
$data = $this->db->select('*')
->from('order_items,SUM(qty) as total_qty')
->order_by('total_qty','desc')
->limit(5)
->group_by('product_id')
->get()->result_array();

I found my own solution using php in case some one else stumbles upon this. If there is a better way to do this using mysql I would be glad to learn something. Here is my php function getting the results I need.
$query = $this -> db -> get('order_items');
$array = array();
foreach ($query -> result() as $result) {
$key = $result -> product_id;
$value = $result -> qty;
if (!isset($array[$key])) {
$array[$key] = $value;
} else if (array_key_exists($key, $array)) {
$old = $array[$key];
$array[$key] = $value + $old;
}
}
arsort($array);
$newArray = array_slice($array, 0, 5, true);
return $newArray;
In the last few hours I have done some mysql tutorials and learned a lot about join, order and limit. Below is what I finally used to get what I needed.
$select = array('products.name as label', 'sum(order_items.qty) as value');
$final = $this -> db -> select($select)
-> from('products')
-> join('order_items', 'order_items.product_id = products.id', 'left')
-> group_by('products.id')
-> order_by('value', 'DESC')
-> limit(5)
-> get() -> result_array();

Try This
$data = $this->db->select('id, product_id, SUM(quantity) as total_qty')
->from('table')
->order_by('total_qty','desc')
->limit(5)
->group_by('product_id')
->get()->result_array();

public function getAllBestsaller() {
$result = array();
$returndata = array();
$this->db->select("*, SUM(total_sale) as total_sale");
$this->db->from("{$this->tblproducts}");
$this->db->where('isactive', 1 );
$this->db->order_by('total_sale','desc');
$this->db->limit(2);
$this->db->group_by('product_id');
$aQuery = $this->db->get();
$this->db->last_query();
if($aQuery -> num_rows() >0 ){
$returndata = $aQuery->result();
}
return $returndata;
}

Related

Querying sum of multiple aggregate columns (without groupBy)

I have a transactions table and I'm trying to get the total of each type.
To simply put it looks like this
id
type
credit_movement
1
top_up
10000
2
fee
-50
3
deduct
-1000
I am trying to get sum of each type to show as a report.
top_up: 10000
fee: 50
deduct: 1000
net_expense: 9850 [top_up - deduct - fee]
$types = [
'top_up' => ['top_up'],
'deduct' => ['deduct'],
'fee' => ['fee'],
'net_expense' => ['top_up', 'deduct', 'fee'],
];
$query = DB::table('transactions');
foreach ($types as $type => $fields) {
$query->selectSub(function ($query) use ($fields) {
return $query->selectRaw('SUM(credit_movement)')->whereIn('type', $fields);
}, $type);
};
$results = $query->get();
When I do this, I get:
1140 In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'project.transactions.type'; this is incompatible with sql_mode=only_full_group_by..
When I change my database.mysql.strict = false, it works; however I want to make it work properly without needing to change the mysql config.
As of my understanding, this error indicates that I am only selecting aggregated columns, but in my case I don't actually want to groupBy() anything as this is just reports.
If I try to groupBy('type') it returns everything grouped by type, but the queries are only run within that group.
{
0: {
top_up: 10000,
deduct: 0,
fee: 0,
net_expense: 10000
}
1: {
top_up: 0,
deduct: -1000,
fee: 0,
net_expense: -1000
},
// etc...
}
Is there a way to obtain without changing strict to false?
{
0 => {
top_up: 10000,
deduct: -1000,
fee: -50,
net_expense: 9850
}
}
If I understand you correctly this might be very easy but again I might have not understood it right.
$result = DB::table('transactions')->selectRaw('type, SUM(credit_movement) as sum')->groupBy('status')->get();
This should return something like this:
type
sum
fee
-5656
topup
8758
deduct
-7625
For the total sum you can just do it in php which would make it easier
$net = $result->sum('sum'); // equals -5656+8758-7625
Hope this helps and let me know if I am wrong about it.
The problem with your approach is in the final column that is the sum of the other 3 so you can't use SUM because you don't have a column to group.
You could use a subquery but I think that the best solution is to add a little elaboration of the raw data that you get from a simpler query.
$query = DB::table('transactions')
->selectRaw('type, SUM(credit_movement) AS movements')
->groupBy('type');
$results = array_reduce($query->get(), function(array $res, array $value){
$res[$array['type']] = $array['movements'];
return $res;
}, []);
$results['net_expense'] = array_sum($results);

match the array from DB column with another DB table column in laravel

I'm getting data through the 2 table in form of array (like address) and one to find particular pin code in another table here is the 2 model that i'm using to find and match the result and perform the tax function eg. if one table have the array a.b,c,d the second table have the value to find the value store in it eg. if a = 1 if b=2 like that here is my code idea trying to implement but no success
try
{
$toltax = toltax::wheresource('LIKE','%'.$s_address.'%')->get();
$tsource = $toltax->source;
$tdestination = $toltax->destination;
if(!empty($toltax = toltax::where($s_address, 'LIKE' ,"%$tsource%")
->where($d_address,'LIKE',"%$tdestination%")
->get('tax')
)
){
Log::info("toll tax".$toltax->tax);
$Tax = $Tax + $toltax->tax;
}
}catch(ModelNotFoundException $e) {
return false;
}
try this i hope help you
$tax = DB::table('toltax as latest')
->whereSource('LIKE','%'.$s_address.'%')
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('toltax')
->whereRaw('source LIKE latest.source')
->whereRaw('destination LIKE latest.destination');
})
->get(['tax']);

Using preg_replace in laravel

I have database data like text [mydata] some text [otherdata] some more text and I want to replace those [mydata] , [otherdata] with dynamic info such as category title for instance.
So the result of my data would be like:
text Category Title some text Category Desc some more text
instead of
text [mydata] some text [otherdata] some more text
I think that can be happen by preg_replace but not quite sure.
code
View::composer('*', function ($view) {
$notes = Notes::all();
foreach($notes as $note){
$descrip= $note->description;
}
$view->with('descrip', $descrip);
});
More
So basically $note->description content is this data:
text [mydata] some text [otherdata] some more text
I want to replace those elements by data from categories table.
Any idea?
Update
well i was digging and get code below (useing str_replace) however it has some issues,
View::composer('*', function ($view) {
//getting categories and pull out the values i want to use as `[....]`
$catC = Category::all();
foreach($catC as $catD){
$meta_title = $catD->title;
$meta_desc = $catD->meta_description;
$meta_tags = $catD->meta_tags;
}
//replace those categories values with element in database `[......]`
$seotemplates = SeoTemplate::all();
foreach($seotemplates as $seotemplate){
$myCustom = str_replace_array('[cattitle]', [$meta_title, $meta_desc, $meta_tags], $seotemplate->categories_desc_template);
}
$view->with('myCustom', $myCustom);
});
Issues
I can only get [cattitle] but what about [catmeta] & [cattags]?
$meta_title will always return first value from categories table (for example if i'm visiting HP category page it return ACER as [cattitle] or any other category pages i visit. It's always ACER
Update 2
I solved the issue 1 of my first update but still issue 2 remained, here is updated code
View::composer('*', function ($view) {
//categories
$catC = Category::all();
$catD = [];
foreach($catC as $catD){
$catD = [
$cattitle = $catD->title,
$catmeta = $catD->meta_tags,
$catdesc = $catD->meta_description
];
}
$a1 = array("[cattitle]","[catmeta]","[catdesc]");
$seotemplates = SeoTemplate::all();
foreach($seotemplates as $seotemplate){
$myCustom = str_replace($a1, $catD, $seotemplate->categories_desc_template);
}
$view->with('myCustom', $myCustom);
});
Current issue:
$meta_title will always return first value from categories table (for example if i'm visiting HP category page it return ACER as
[cattitle] or any other category pages i visit. It's always ACER
I see a couple of issues with your code that I think will help with getting the solution that you are after.
First like mentioned by #hktang said in his comment you are duplicating your variables and then assigning it's value over and over again instead of adding to it. Try this:
$catE = [];
foreach($catC as $catD){
$catE[] = [
$cattitle = $catD->title,
$catmeta = $catD->meta_tags,
$catdesc = $catD->meta_description
];
}
Second you are also resetting the value of $myCustom with each loop of the for each. Try this:
$myCustom = []
foreach($seotemplates as $seotemplate){
$myCustom[] = str_replace($a1, $catE, $seotemplate->categories_desc_template);
}
This should result in you getting an array of seotemplates with the values replaced but I have not testing this.

Very Complex SQL Data Result Merge via PHP (Multi Dimentional Arrays)

Sorry, I have a hard time to write proper thread title for this problem.
Here's my question:
In short: How to merge array item and calculate.
Here's the full explanation
1) I have a (WP custom) database to track statistics: visits, unique visits, etc, and it's stored per post per date.
To make it easier to understand. Here's the screenshot of the table:
2) This is the example data when I queried it:
https://gist.github.com/turtlepod/8e7dc93bae7f0b665fd5aea8a9694998
So in this example we have multiple post ID: "90", "121", & "231"
We have multiple date in db: "2017-03-20", "2017-03-21", "2017-03-22"
We have multiple stats: "visits", and "unique_visits"
We also have a "stat_value" for each item.
Each item have unique ID.
All data is dynamically created when an event happen. so not all post_id have 2 stats or the above date.
Note: keep in mind that in real code, we have a lot more data and variations than the example above.
3) I need to merge the data:
The post_id "121" is the same as post "231", so we need to merge and add the "stat_value" into one data and remove "231" entry.
What is the best way to do this (dynamically) via PHP ?
I have this data:
$raw_data = array( ... ); // the one in github gist
$post_groups = array(
'121' => array( '121', '231' ), // main post_id => array of alias.
);
It need to return the same data format as $raw_data, but remove the data of "231" and include/sum the "stat_value" of "231" to "121".
Thank you.
Try it with this:
function david_transform_data($data, $groups) {
if (empty($groups) === true) {
return $data;
}
// Transform groups into a more useful format
$transformed_groups = array();
foreach ($groups as $post_id => $aliases) {
foreach ($aliases as $alias) {
if (absint($post_id) === absint($alias)) {
continue;
}
$transformed_groups[absint($alias)] = $post_id;
}
}
// Replace aliases with the real post id
foreach ($data as $index => $stat) {
if (isset($transformed_groups[absint($stat->post_id)]) === false) {
continue;
}
$data[$index]->post_id = $transformed_groups[absint($stat->post_id)];
}
// Go through stats and merge those with the same post_id, stat_id
// and stat_date
$merged_stats = array();
$index_tracker = 0;
$stats_hash = array();
foreach ($data as $index => $stat) {
$hash_key = sprintf(
'%s-%s-%s',
$stat->post_id,
$stat->stat_id,
$stat->stat_date
);
if (isset($stats_hash[$hash_key]) === true) {
$merged_stats[$stats_hash[$hash_key]]->stat_value += absint($stat->stat_value);
continue;
}
$merged_stats[] = $stat;
$stats_hash[$hash_key] = $index_tracker;
$index_tracker++;
}
return $merged_stats;
}
var_dump(david_transform_data($raw_data, $post_groups));
There might be a faster solution but this is the first thing that came to my mind.

Sum of Foreach Loop

I'm trying to total a bill balance with a program I'm working on in PHP.
The code I use to pull the pricing is as such.
public function PackagePricing($arg) {
$query = <<<SQL
SELECT packageID
FROM customer_packages
WHERE active = :true
AND customerID = :arg
SQL;
$resource = $this->db->db->prepare( $query );
$resource->execute( array (
":true" => 1,
":arg" => 1,
));
foreach($resource as $row) {
self::GetPricing($row['packageID']);
}
}
public function GetPricing($arg) {
$query = <<<SQL
SELECT price
FROM products
WHERE id = :arg
SQL;
$resource = $this->db->db->prepare( $query );
$resource->execute( array (
":arg" => $arg,
));
$totalBill = 0;
foreach($resource as $row) {
$totalBill+= $row['price'];
}
echo $totalBill;
}
Now by my understanding this should work, but what I'm getting in turn is:
On the right you can see the billing total and rather than totaling out it's giving me each individually.
The error seems quite obvious. Here's your sequence in different words :
Get all packages ID.
Foreach package ID, get the price of the item (only one result is returned)
For that single result, add up all the prices (you only get one). Print it and go back to 2.
What you see is not 2 prices that have been added as strings in some sort of way. You simply prints subsequently 2 different prices. 10 & 30
GetPricing should return a price, and the foreach loop that calls it should make the sum.
$total = 0;
foreach($resource as $row)
{
$total += self::GetPricing($row['packageID']);
}
Hope this helps.

Categories