DB::select("select encoded_datas.* from encoded_datas inner join
(select data_user_firstname, data_user_lastname, data_user_barangay from encoded_datas t
group by data_user_firstname, data_user_lastname, data_user_barangay
having count(*)>1) t1
on encoded_datas.data_user_firstname=t1.data_user_firstname and encoded_datas.data_user_lastname=t1.data_user_lastname and encoded_datas.data_user_barangay=t1.data_user_barangay");
It's a working piece of query code, but it is so slow to load compare to Eloquent/Proper Query Builder.
Can anyone here help me convert this to Laravel's Query Builder format..
try this solution
DB::connection(your_connection)
->table('encoded_datas')
->select('encoded_datas.*')
->join(
DB::raw("SELECT data_user_firstname, data_user_lastname, data_user_barangay FROM encoded_datas t GROUP BY data_user_firstname, data_user_lastname, data_user_barangay HAVING COUNT(*) > 1) t1"),
function($join {
$join->on('encoded_datas.data_user_firstname', '=', 't1.data_user_firstname')
->on('encoded_datas.data_user_lastname', '=', 't1.data_user_lastname')
->on('encoded_datas.data_user_barangay', '=', 't1.data_user_barangay');
})
)
but I don't think it will speed up execution
Sometimes sending multiple requests might be less expensive then sending one nested.
You can try getting the ids of the duplicate rows first
$ids = DB::table('datas')
->select('firstname','lastname', DB::raw('COUNT(*) as `count`'))
->groupBy('firstname', 'lastname')
->havingRaw('COUNT(*) > 1')
->pluck('id');
Then get datas
$datas = Datas::whereIn('id', $ids)->get();
In your example you are executing two queries and a join.
Here we are executing 2 queries only, 1 of which uses primary key index, which should be instant. Technically its should be faster, looks cleaner as well
I've tried Alexandr's code:
$ids = DB::table('datas')
->select('firstname','lastname', DB::raw('COUNT(*) as `count`'))
->groupBy('firstname', 'lastname')
->havingRaw('COUNT(*) > 1')
->pluck('id');
$datas = Datas::whereIn('id', $ids)->get();
But it only shows single data/record.. What i want to get is something like this:
**id** |firstname |lastname
1 | John | Legend
2 | john | Legend
3 | Michael | Mooray
4 | Smith | West
5 | smith | West
so Im expecting to get the following result:
john |Legend
john |Legend
Smith |West
Smith |West
Related
I am trying to get how many names do I have in database. For this purpose I am using Query Builder like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->count();
Is says that 24, which is not correct, because if I will write code like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
result object contains 247 elements, which is correct. I have tried to play with skip/take, but still no results. Where am I wrong? Thanks for any help.
I think it's the other way around, you're not getting 24 groups. You're getting 24 elements within the first group. That configuration results in the following query:
SELECT
COUNT(*) AS 'aggregate',
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`;
What you end up with will look something like this:
+---------------+---------+
| aggregate | name_id |
+---------------+---------+
| 24 | 1 |
+---------------+---------+
| 5 | 2 |
+---------------+---------+
| 30 | 3 |
+---------------+---------+
| ... and so on | 4 |
+---------------+---------+
Query\Builder just doesn't realize you can get more than one result back when count() is involved.
You were pretty close to the right answer yourself though.
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
get() returns an Eloquent\Collection, child of Support\Collection, which has its own version of the count method. So your answer is just:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get()
->count();
If you really want this to happen in MySQL, the query you want to happen would look like this:
SELECT COUNT(*) FROM (
SELECT
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`
) AS temp;
For that, you can do this:
$query = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having);
$sql = $query->toSql();
$values = $query->getBindings();
$count = DB::table(DB::raw('('.$sql.') AS `temp`'))
->selectRaw("COUNT(*) AS 'aggregate'", $values)
->first()
->aggregate;
MySQL performance can get a little hairy when asking it to write temp-tables like that though, so you'll have to experiment to see which option is faster.
Inuyaki is right
(id, name_id),
(1,1),
(2,1),
(3,2),
(4,3)
There are are four rows so get() method will return 4 rows
but there are three groups if you use groupBy [name_id]
1 (1,1)
2 (2)
3 (3)
now count will return 3
hope this will help.
I am pulling my hair out over this one, and I feel like I have tried every method!
Here is my problem.
I have 2 tables
USERS
ID | FIRSTNAME | EMAIL_ADDRESS
1 | Joe Bloggs | joe#bloggs.com
STATUS
ID | USER_ID | STATUS | DATE
1 | 1 | 'In' | 2018-06-04 09:01:00
2 | 1 | 'Out' | 2018-06-04 09:00:00
As you can see by the tables above, each user can have many status', but each user has to have 1 most recent status, which I am doing like this (please tell me if I am doing it wrong)
public function statusCurrent(){
return $this->hasOne('App\Status', 'user_id', 'id')->orderBy('date', 'desc')->limit(1);
}
I then a form on in my view, which passes filters to the controller via a $request.
I need to be able to use the filters, and apply them to the 1 most recent status. For example, if someone searches for the date 2018-06-04 09:00:00 and a user id 1, I need it to show NO RESULTS, because the 1 most recent record for that user does not match that date, but at the moment, it will just jump over the one most recent if it doesn't match, and get the next record that does.
I have tried what seems like every method, I have tried like this
$users = Users::with(['StatusCurrent' => function($query){
$query->where('status.status', 'In');
}])->get();
Which gets the correct most recent row, but then if i try status.status, 'out' instead, it just jumps over and gets record number 2 where the status is out.
I've also tried like this
$users = Users::has('StatusCurrent')->paginate(10);
if(!empty($request->statusIn)){
$users = $users->filter(function ($item){
$item = $item->statusCurrent->status == 'in';
return $item;
});
}
return $users;
Which works great but then the pagination breaks when trying to append any GET parameters for the filters.
Plain English
I need to be able to get the most recent status for the user, then once I have it, I need to be able to apply where statements/filters/arguments to it, and if they don't match, completely ignore that user.
You have to combine a JOIN with a subquery:
$users = User::select('users.*')
->join('status', 'users.id', 'status.user_id')
->where('status.status', 'in')
->where('status.id', function($query) {
$query->select('id')
->from('status')
->whereColumn('user_id', 'users.id')
->orderByDesc('date')
->limit(1);
})
->get();
You can get the ID first, then do your query with filters:
$status_id = Users::find($user_id)->statusCurrent()->id;
Now do the actual query, using $status_id in whereHas clause:
$users = Users::with('statusCurrent')
->whereHas('statusCurrent', function($query) use($status_id) {
$query->where('status.status', 'In')
->where('id',$status_id);
})->get();
The relationship should be like:
public function statusCurrent(){
return $this->hasOne('App\Status', 'user_id', 'id')->latestOfMany();}
I want to get all rows which is the same name and location from Users Table
**id** |name |location |phone_number
1 |John | Europe |0988884434
2 |john | Europe |0933333333
3 |Michael |Europe |0888888888
4 |Smith |Dubai |082388888888
5 |Smith |Dubai | 03939494944
I want to get all rows which is the same name and location like
john |Europe
john |Europe
Smith |Dubai
Smith |Dubai
here is how i tried to do
$duplicates = DB::table('users')
->select('name','location', DB::raw('COUNT(*) as `count`'))
->groupBy('name', 'location')
->having('count', '>', 1)
->get();
but this is just showing only one row which is duplicates like
john |Europe
Smith|Dubai
Any help or advice you have would be greatly appreciated.
Use havingRaw:
$duplicates = DB::table('users')
->select('name','location', DB::raw('COUNT(*) as `count`'))
->groupBy('name', 'location')
->havingRaw('COUNT(*) > 1')
->get();
I also wasn't sure of the syntax, but the Laravel documentation seems to imply that the alias you defined in the select clause is not available in the normal having() function.
To get All Rows rather than a total count of a group of duplicate rows would look like the following;
$duplicates = DB::table('users')
->select('id', 'name', 'location')
->whereIn('id', function ($q){
$q->select('id')
->from('users')
->groupBy('name', 'location')
->havingRaw('COUNT(*) > 1');
})->get();
Here is my Table
Id | No |Group
1 | 1 |Alpha
1 | 1,2 |Alpha
1 | 2,4,5|Alpha
How can i find the the row which has No as 5 using laravel eloquent
$Match = MyModel::whereIn('No', array(5))->get();
But it didn't return any rows.
When i try to see the query executed it shows me
select * from `table` where `No` in (5)
How can i do this in php and laravel
As a pure Eloquent workround, you might be able to do something like:
$id = 5
$Match = MyModel::with(array('No' => function($query) use($id) {
$query->where_id($id);
}))->get();
Using Raw and FIND_IN_SET, something like:
$Match = MyModel::whereRaw(
'find_in_set(?, `No`)',
[5]
)->get();
(Untested)
But this will never be an efficient query because it can't use indexes; and there are many other reasons why a comma-separated list is a bad idea (such as lack of referential integrity)
The real solution will always be to normalize your database properly
I'm having a problem at the moment where I have a column called rating in the links table and there is definitely values other than 0 within the column but 0 is the only value which is returned foreach link. When I do a simple get for that column it then shows all the other values but not when I do an SQL Join.
I know the problem is my joining of the tables but I'm unsure how I would go about joining these specific tables.
Database Table Structure
The rating column is the one which is causing me problems.
'links' id | title | url | user_id | list_id | rating | weight | date_created
'list' id | list_title | list_description | user_id | rating | views | date_created
'link_ratings' id | user_id | link_id | rated | date_created
Model:
public function get_latest(){
$this->db->limit(100);
$this->db->order_by('links.date_created', 'DESC');
$this->db->select('*');
$this->db->select('links.id as current_link_id');
$this->db->from('links');
$this->db->join('list', 'links.list_id = list.id');
$this->db->join('users', 'links.user_id = users.id');
$this->db->join('link_ratings', 'links.id = link_ratings.link_id','left');
$get_latest = $this->db->get();
return $get_latest;
}
Any Help is appreciated.
You should try this:
function get_latest(){
$this->db->select('list.*, users.*, links.id as current_link_id');
$this->db->from('links');
$this->db->join('list', 'links.list_id = list.id');
$this->db->join('users', 'links.user_id = users.id');
$this->db->join('link_ratings', 'links.id = link_ratings.link_id','left');
$this->db->order_by('links.date_created', 'DESC');
$this->db->limit(100);
$get_latest = $this->db->get()->result_array(); #fetch all rows here
echo "<pre>";print_r( $get_latest );die; #print all rows and see if its fetching ratings corrctly or not.
echo $this->db->last_query();die; #check the query generated
return $get_latest;
}
The reason will be purely logical, in that the join will be causing no results to be returned because there are no results. I've fallen into this many times.
I am not able to diagnose your particular problem but when faced with issues like this I:
1- turn on the CI profiler
2- var_dump the array so you can see what's going on
3- write a traditional SQL query and run it in PHPMyAdmin
One, or a combination of all three, will enable you to diagnose.