codeigniter LEFT JOIN array issue - codeigniter

Can someone tell me how to write this properly?
function get_tech() {
$this->db->select('u.id
,u.first_name
,us.id
,us.group_id');
$this->db->from('users u');
$this->db->join('users_groups us','us.id = u.id','left');
$records = $this->db->where('us.group_id', '3');
$data=array();
foreach($records->result() as $row)
{
$data[$row->id] = $row->first_name;
}
return ($data);
}
I'm trying to populate a drop down menu using an array, but i need to only grab users that are part of users_group/group_id = 3
therefore in my very limited knowledge I'm needing:
select X from Users LEFT JOIN users_groups WHERE group_ID = 3

You need to call $this->db->get() in order to actually run your query.
function get_tech() {
$this->db->select('u.id
,u.first_name
,us.id
,us.group_id');
$this->db->from('users u');
$this->db->join('users_groups us','us.id = u.id','left');
$this->db->where('us.group_id', '3');
$records = $this->db->get();
$data = array();
foreach($records->result() as $row){
$data[$row->id] = $row->first_name;
}
return $data;
}

Related

Nested loop caused slow in performance

foreach ($id_prs as $ids) {
list($id_pr, $id_cart) = explode('-', $ids);
foreach ($id_cart as $id) {
$r = Cart::find($id);
/// column to update value
$r->save();
}
}
This is how my loop looks like.
E.g. $id_prs consist of 10 data, while each id_prs may consist of 20 data etc.
From there, i found will take longer time to loop when a lots of data from each $id_cart.
How can i solve the performance issue, is there any solution?
This is known as n+1 problem, every time you iterate inside foreach additional query is created.
So this line is the evil, because it's querying data every iteration.
$r = Cart::find($id);
You can make it better like this:
$cart = Cart::all();
foreach ($id_prs as $ids) {
list($id_pr, $id_cart) = explode('-', $ids);
foreach ($id_cart as $id) {
// Get it from collection rather than query it from database
$cart->where('id', $id)->first()->save();
}
}
Where you acctualy query all carts inside variable as a collection, and you just manipulating with that collection localy without touching database (only when you hit save method).
Your code and variables are not clear enough. But a better solution is:
foreach ($id_prs as $ids) {
list($id_pr, $id_cart) = explode('-', $ids);
$items = Cart::whereIn('id', $id_cart) -> get();
foreach($items as $item) {
Cart::where('id', $item -> id) -> limit(1) -> update([
// Columns to update
]);
}
}
If you want to update same value for all the records
$allIds = [];
foreach ($id_prs as $ids) {
list($id_pr, $id_cart) = explode('-', $ids);
foreach ($id_cart as $id) {
$allIds[] = $id;
}
}
$cart = Cart::whereIn('id',$allIds)->update(['columns'=>'value']);

Showing the lowest pid / parent id number first

I have this function below which get the pid numbers from my database. The pid is parent id.
public function test() {
$arr = array();
foreach ($this->make_parent_list() as $result) {
$arr[] = $result;
}
print_r(implode(',', $arr));
}
The out put is as follows 4, 1
But I need it to print the lowest number first. 1, 4
Question How can I make sure when i view the parent id / pid that it
will show the lowest number first I have tried
$this->db->order_by('pid', 'desc'); and $this->db->order_by('pid',
'asc');
public function make_parent_list() {
$this->db->where('fid', '5');
$query = $this->db->get('forum');
$return = array();
foreach ($query->result() as $category)
{
$this->db->where('fid', $category->pid);
$this->db->order_by('pid', 'desc');
$query = $this->db->get('forum');
$return[$category->pid] = $category->pid;
foreach ($query->result() as $category)
{
$return[$category->pid] = $category->pid;
}
}
return $return;
}
Solved
I had to created a $results variable and then wrap in sort() outside foreach loop
$arr = array();
$results = $this->make_parent_list();
sort($results);
foreach ($results as $result) {
$arr[] = $result;
}
echo implode(',', $arr);
Now out put 1,4
I think you got a bit lost... The order_by asc,desc does work. Your function has order_by desc and an unnecessary foreach etc.
Assumptions: The forum table has at least the two columns pid and fid. I created a table with
fid , pid
5 1
5 4
If you simplify your function to...
// Given the fid, return an array of pid values in ascending order
public function make_parent_list() {
$this->db->where('fid', '5'); // Hardcoded for testing.
$this->db->order_by('pid', 'asc');
$query = $this->db->get('forum');
$pid_list = array();
foreach ($query->result() as $category) {
$pid_list[] = $category->pid;
}
return $pid_list;
}
Then you only need
$results = $this->make_parent_list();
echo implode(',', $results);
That will give you a result of 1,4.
If you change asc to desc in the order_by in the function then you will get 4,1.

Not getting correct SUM amount for users votes from thread and reply table

I am using codeigniter 3.1.0 and I am trying to get the total SUM of two columns from different tables
If my user_id = 1 it should return the total sum of 421 but returns 431 It is adding the votes from other users on my reply table
Question Using Active Record How can I make sure the SUM is getting the correct amount for the users id.
Model Function
public function thread_reputation($user_id) {
$this->db->select('SUM(reply.votes + thread.votes) AS reputation');
$this->db->from('thread', 'left');
$this->db->join('reply', 'reply.user_id = thread.user_id', 'left');
$this->db->where('thread.user_id', $user_id);
$this->db->where('reply.user_id', $user_id);
$query = $this->db->get();
if ($query->num_rows() > 0) {
return $query->row();
} else {
return 0;
}
}
Controller section where i echo it
$thread_reputation = $this->thread_analytics_model->thread_reputation('1');
echo $thread_reputation->reputation;
Thread Table
Reply Table
Change your query with this
$query = $this->db->query("SELECT SUM(A.votes) as reputation from
(
SELECT reply.votes FROM reply where reply.user_id = $user_id
UNION ALL
SELECT thread.votes FROM thread where thread.user_id = $user_id
)AS A");
Tested and properly working
Check Screenshot:-
Query using ACTIVE REOCRD
$this->db->select("SUM(A.votes) as reputation");
$this->db->from("(
SELECT reply.votes FROM reply where reply.user_id = $user_id
UNION ALL
SELECT thread.votes FROM thread where thread.user_id = $user_id) AS A");
$query = $this->db->get();
Another Solution using $this->db->get_compiled_select();
public function reputation($user_id) {
$this->db->select('thread.votes');
$this->db->from('thread');
$this->db->where('thread.user_id =' . $user_id);
$thread_query = $this->db->get_compiled_select();
$this->db->select('reply.votes');
$this->db->from('reply');
$this->db->where('reply.user_id ='. $user_id);
$reply_query = $this->db->get_compiled_select();
$query = $this->db->query("SELECT SUM(total.votes) as reputation from ($reply_query UNION ALL $thread_query) as total");
if ($query->num_rows() > 0) {
return $query->row();
} else {
return 0;
}
}
When you will use left join, it will return matched column & all other unmatched column from left table. Use inner join & check your result.

Laravel how do I get the row number of an object using Eloquent?

I'd like to know the position of a user based on its creation date. How do I do that using Eloquent?
I'd like to be able to do something like this:
User::getRowNumber($user_obj);
I suppose you want MySQL solution, so you can do this:
DB::statement(DB::raw('set #row:=0'));
User::selectRaw('*, #row:=#row+1 as row')->get();
// returns all users with ordinal 'row'
So you could implement something like this:
public function scopeWithRowNumber($query, $column = 'created_at', $order = 'asc')
{
DB::statement(DB::raw('set #row=0'));
$sub = static::selectRaw('*, #row:=#row+1 as row')
->orderBy($column, $order)->toSql();
$query->remember(1)->from(DB::raw("({$sub}) as sub"));
}
public function getRowNumber($column = 'created_at', $order = 'asc')
{
$order = ($order == 'asc') ? 'asc' : 'desc';
$key = "userRow.{$this->id}.{$column}.{$order}";
if (Cache::get($key)) return Cache::get($key);
$row = $this->withRowNumber($column, $order)
->where($column, '<=',$this->$column)
->whereId($this->id)->pluck('row');
Cache::put($key, $row);
return $row;
}
This needs to select all the rows from the table till the one you are looking for is found, then selects only that particular row number.
It will let you do this:
$user = User::find(15);
$user->getRowNumber(); // as default ordered by created_at ascending
$user->getRowNumber('username'); // check order for another column
$user->getRowNumber('updated_at', 'desc'); // different combination of column and order
// and utilizing the scope:
User::withRowNumber()->take(20)->get(); // returns collection with additional property 'row' for each user
As this scope requires raw statement setting #row to 0 everytime, we use caching for 1 minute to avoid unnecessary queries.
$query = \DB::table(\DB::raw('Products, (SELECT #row := 0) r'));
$query = $query->select(
\DB::raw('#row := #row + 1 AS SrNo'),
'ProductID',
'ProductName',
'Description',
\DB::raw('IFNULL(ProductImage,"") AS ProductImage')
);
// where clauses
if(...){
$query = $query->where('ProductID', ...));
}
// orderby clauses
// ...
// $query = $query->orderBy('..','DESC');
// count clause
$TotalRecordCount = $query->count();
$results = $query
->take(...)
->skip(...)
->get();
I believe you could use Raw Expresssions to achieve this:
$users = DB::table('users')
->select(DB::raw('ROW_NUMBER() OVER(ORDER BY ID DESC) AS Row, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
However, looking trough the source code looks like you could achieve the same when using SQLServer and offset. The sources indicates that if you something like the following:
$users = DB::table('users')->skip(10)->take(5)->get();
The generated SQL query will include the row_number over statement.
[For Postgres]
In your model
public function scopeWithRowNumber($query, $column = 'id', $order = 'asc'){
$sub = static::selectRaw('*, row_number() OVER () as row_number')
->orderBy($column, $order)
->toSql();
$query->from(DB::raw("({$sub}) as sub"));
}
In your controller
$user = User::withRowNumber()->get();

get the last row in the db

What is the correct way to retrieve the last row, sorted desc by id, in CodeIgniter?
I've tried select_max but I want the whole row.
function getLastPagination(){
$data = array();
$this->db->query("SELECT id,sort FROM pagination GROUP BY id DESC LIMIT 1");
$query = $this->db->get('pagination');
$data = $query->row_array();
return $data;
}
$data['allpag'] = $this->Model_cats->getLastPagination();
$data['pagin'] = $data['allpag']['sort'];
$per_page = $data['pagin'];
Here I am getting the first value, but I want the last row.
$this->db->select('id')->order_by('id','desc')->limit(1)->get('table_name')->row('id');
Try this.............
function getLastPagination(){
$query ="select * from pagination order by id DESC limit 1";
$res = $this->db->query($query);
if($res->num_rows() > 0) {
return $res->result("array");
}
return array();
}
}
In controller function you need to do following things.......
$allpag = $this->Model_cats->getLastPagination();
$per_page = $allpag[0]['sort'];
$query = $this->db->query("SELECT * FROM pagination ORDER BY id DESC LIMIT 1")->row_array();
Should work?

Resources