Laravel 5.2 trouble with SQL query in eloquent - php

I am having trouble with eloquent in Laravel 5.2
What I want to achieve is (hopefully) a query which fulfills these steps:
updated_at >= value1
updated_at <= value2
event = value3
groupBy = value4
count entries of each "group" (each grouped By group)
Output: latest updated_at for each group (max(updated_at)) and the count value for each group
What I have so far is:
Table 'logs' overview:
---------------------------
| id | increment |
-----------------------------
| key | varchar(255) |
-----------------------------
| video_id | varchar(255) |
-----------------------------
| event | varchar(255) |
-----------------------------
| created_at | timestamp |
-----------------------------
| updated_at | timestamp |
-----------------------------
Query in Laravel:
$showed = self::where('updated_at','>=',$value1)->where('updated_at','<=',$value2)->where('event',$value3)->groupBy($avlue4)->get();
What I am missing are step 5 and the resulting output. And I have no idea how I could include this to the Laravel eloquent.
Question: Does anyone have a concrete idea of how to achieve this query? If it's not possible, what are the steps to take?

You may pass an array of conditions like this:
$showed = DB::table('tableNameHere')->where([
['updated_at', '>=', $month_start],
['updated_at', '<=', $month_end],
['event', '=', 'showed'],
])->groupBy('id')->get();
To count the entries you can then try it this way:
$results = $showed->count();
Couldn't test the code. Let me know if this worked.

If someone also has troubles with building this kind of eloquent: My solution was to group the query by ID, so the entries in Array would be something like:
[0] => [Object, Object],
[1] => [Object]
My query:
$temp = self::where('updated_at','>=',$month_start)
->where('updated_at','<=',$month_end)
->where('event','completed')
->orWhere('event', 'showed')->get();
$result = $temp->groupBy('id')->toArray();;

Related

Laravel Eloquent GroupBy Name to Create array of ID's

I have a table in my Laravel application which I wish to query.
id | company_name | contact |
-----------------------------
1 | Tesco | Name 1 |
2 | Tesco | Name 2 |
3 | Asda | Name 3 |
4 | Tesco | Name 4 |
5 | Asda | Name 5 |
I'm trying to get an array of all unique company names with all ID numbers.
'Tesco' => [1,2,4]
'Asda' => [3,5]
I have tried
$companies = Contact::select('company_name','id')->groupBy('company_name')->get();
However this requests the 'id' to be included in the group by which defeats the purpose. I understand it's asking for this because it's not a SUM or COUNT etc.
The above table may seem unusual and I know I should have a relation to a companies table however this is necessary at this stage.
You could use GROUP_CONCAT()
$companies = Contact::select('company_name', DB::raw('GROUP_CONCAT(id) as ids'))
->groupBy('company_name')
->get();
This would return something like:
company_name | ids
Tesco | 1,2
Edit: if you want the ids in the form an array, you could just map over the collection to convert it:
$companies->map(function($column) {
$column->ids = explode(',', $column->ids);
});
That should do the trick.

Retrieve entries from table via pivot table Octobercms

can anyone help me writing query to retrieve words from my words table in such way that words are having a belongsToMany relationship to Type model via types pivot table?
Here's how relationship looks like in Word.php
public $belongsToMany = [
'typeswb' => [
'Yeoman\Wordbank\Models\Type',
'table' => 'yeoman_wordbank_types_pivotb',
'order' => 'typesofwordbank'
]
];
Here is how types table looks like
mysql> select * from yeoman_wordbank_types;
+----+--------------------+--------------------+
| id | typesofwordbank | slugoftypes |
+----+--------------------+--------------------+
| 1 | Common Words | common-words |
| 2 | Common Expressions | common-expressions |
| 3 | Common Proverbs | common-proverbs |
| 4 | Common Idioms | common-idioms |
+----+--------------------+--------------------+
4 rows in set (0.00 sec)
and wheres how types pivot table looks like
mysql> select * from yeoman_wordbank_types_pivotb;
+---------+---------+
| word_id | type_id |
+---------+---------+
| 18 | 2 |
| 5 | 4 |
| 9 | 3 |
| 19 | 1 |
| 31 | 1 |
+---------+---------+
5 rows in set (0.00 sec)
As you can see type_id are connected to words_id. where types_id's are from types table and words_id's are from word table.
I need to find a way to get the words using types_id.
I have tried following
// $query = Word::all();
// foreach ($query->typeswb as $typeswb) {
// $queryy = $typeswb->pivot->type_id = 1;
// }
and some other combination like that but all in vain, strangely I get Word::find(1) null on this while Word::all() return an array of 6 items in the collection.
Thank you for reading, I will appreciate any hint or help very much.
You can provide pivot table:
public $belongsToMany = [
'typeswb' => [
'Yeoman\Wordbank\Models\Type',
'table'=>'yeoman_wordbank_types_pivotb',
'key' =>'word_id ',
'otherKey' => 'type_id ',
'pivot' => ['word_id ', 'type_id '],
],
];
ok so i solved this, normally via builder component, this functionality is very easy to achieve but was kinda of unclear how to do on my own in one of my own component. So, here's how i solved this:
$query = Word::whereHas('typeswb', function($q)
{
$q->where('type_id', '=', post('typesofwordsearch')); //post('typesofwordsearch') return integer which are id's of types according to the table
})->limit(5)->get();
Breakdown about how it is working:
So, there could be another way but after trying long, this one worked.
Firstly i am using my Word model where in the word model, i have typeswb which is defining belongToMany relation (see question for that). I am using whereHas read this for more info on that. Basically using wherehas i am instructing query to look up with relation. Afterwards, In function closure, I'm queries using one of key of my types table i.e type_id. For keys of types table again see my question above.
Hope that this will help someone. Cheers!

Laravel orderBy with same value result keep changing

I've try to sort my result within the updated_at value. Because I seed the value all the updated_at value is same:
// Amount Table
-----------------------------------------------------
| id | amount | updated_at |
+----------+--------------------+-------------------+
| 1 | 232319 |2016-02-02 13:17:29|
| 2 | 232319 |2016-02-02 13:17:29|
| 3 | 100000 |2016-02-02 13:17:29|
| 4 | 231111 |2016-02-02 13:17:29|
| 5 | 12345 |2016-02-02 13:17:29|
+----------+--------------------+-------------------+
The problem is everytime I query :
$lists = Amount::orderBy('updated_at', 'DESC')->lists('id')->toArray();
I expect the result to be like this: [1,2,3,4,5] but it appear the result is sometime like that but sometime [2,3,1,4,5]. it keep randoming the result.
As far as i know, yes i can put another orderBy statement to the query, but isn't it suppose to be default it will order by the id?
Thanks
You are only ordering by updated_at which appear to all have the same value. If you want consistency, include a second column
$lists = Amount::orderBy('updated_at', 'DESC')->orderBy('id', 'ASC')->lists('id')->toArray();

Using nested queries and many to many relationships in Doctrine's QueryBuilder

So I'm having a bit of trouble thinking of how to approach this using a query builder. Currently, I have three objects that are the following:
HelpRequest
id
...
status
Filter
id
name
statuses -> ManyToMany(targetEntity="Status")
Status
id
name
A filter can have multiple statuses so there is a table that is keeping track what statuses are part of a specific filter.
Sample Data
help_requests
---
| id | content | status |
| 1 | hello | 3 |
filters
---
| id | name |
| 1 | Active |
| 1 | Inactive |
statuses
---
| id | name |
| 1 | Open |
| 2 | Closed |
| 3 | Waiting User Response |
status_filter
---
| status_id | filter_id |
| 1 | 1 |
| 3 | 1 |
| 2 | 2 |
The status_filter table is automatically generated from a ManyToMany relationship in doctrine between a Status object and a Filter object.
Based on the given information, I've written this SQL query but now I'm having troubles writing this with QueryBuilder.
SELECT * FROM help_requests WHERE status IN (SELECT status_id FROM status_filter WHERE filter_id = 1)
If there's any more information I can give, let me know. I've read multiple questions on SO and have tried a number of things but I can't seem to get it right. I'm aware I could just hard coded that query but I'd like the experience using QueryBuilder
Thanks for the help!
Update
In the end, since I couldn't get it to work with QueryBuilder and I didn't want to create a new entity solely to map two other entities together, I decided to use createQuery() instead and this is what I came up with:
SELECT
hr
FROM
HelpRequest hr
WHERE
hr.status
IN (
SELECT
s.id
FROM
Filter f
JOIN
f.statuses s
WHERE
f.name = :name
)
Thank you everyone for the help.
Try this query, and put is in your HelpRequestsRepository class:
$subquery = $this->->select('st.status_id')
->from('/path/to/StatusFilter', 'st')
->where('st.filter_id = 1');
$query = $this->createQueryBuilder('hr')
->select('*')
->where('hr.status IN (' . $subquery->getDQL() . ')')
->getQuery();
Try this approach in the HelpRequestsRepository class:
$qb = $this->createQueryBuilder('hr');
$qb->select("hr");
$qb->join("::Status","s",Expr\Join::INNER_JOIN, "hr.status=s" );
$qb->join("::Filter","f",Expr\Join::INNER_JOIN, "s.filters=f" );
$qb->where("f.name = :name");
$qb->setParameter('name', $nameOfTheFilterToBeFound)
Hope this help

Merge and Sort two Eloquent Collections?

I've two Collections and I want merge it to one variable (of course, with ordering by one collumn - created_at). How Can I do that?
My Controllers looks that:
$replies = Ticket::with('replies', 'replies.user')->find($id);
$logs = DB::table('logs_ticket')
->join('users', 'users.id', '=', 'mod_id')
->where('ticket_id', '=', $id)
->select('users.username', 'logs_ticket.created_at', 'action')
->get();
My Output looks for example:
Replies:
ID | ticket_id | username | message | created_at
1 | 1 | somebody | asdfghj | 2014-04-12 12:12:12
2 | 1 | somebody | qwertyi | 2014-04-14 12:11:10
Logs:
ID | ticket_id | username | action | created_at
1 | 1 | somebody | close | 2014-04-13 12:12:14
2 | 1 | somebody | open | 2014-04-14 14:15:10
And I want something like this:
ticket_id | table | username | message | created_at
1 |replies| somebody | asdfghj | 2014-04-12 12:12:12
1 | logs | somebody | close | 2014-04-13 12:12:14
1 | logs | somebody | open | 2014-04-14 11:15:10
1 |replies| somebody | qwertyi | 2014-04-14 12:11:10
EDIT:
My Ticket Model looks that:
<?php
class Ticket extends Eloquent {
protected $table = 'tickets';
public function replies() {
return $this->hasMany('TicketReply')->orderBy('ticketreplies.created_at', 'desc');
}
public function user()
{
return $this->belongsTo('User');
}
}
?>
A little workaround for your problem.
$posts = collect(Post::onlyTrashed()->get());
$comments = collect(Comment::onlyTrashed()->get());
$trash = $posts->merge($comments)->sortByDesc('deleted_at');
This way you can just merge them, even when there are duplicate ID's.
You're not going to be able to get exactly what you want easily.
In general, merging should be easy with a $collection->merge($otherCollection);, and sort with $collection->sort();. However, the merge won't work the way you want it to due to not having unique IDs, and the 'table' column that you want, you'll have to make happen manually.
Also they are actually both going to be collections of different types I think (the one being based on an Eloquent\Model will be Eloquent\Collection, and the other being a standard Collection), which may cause its own issues. As such, I'd suggest using DB::table() for both, and augmenting your results with columns you can control.
As for the code to achieve that, I'm not sure as I don't do a lot of low-level DB work in Laravel, so don't know the best way to create the queries. Either way, just because it's looking like starting to be a pain to manage this with two queries and some PHP merging, I'd suggest doing it all in one DB query. It'll actually look neater and arguably be more maintainable:
The SQL you'll need is something like this:
SELECT * FROM
(
SELECT
`r`.`ticket_id`,
'replies' AS `table`,
`u`.`username`,
`r`.`message`,
`r`.`created_at`
FROM `replies` AS `r`
LEFT JOIN `users` AS `u`
ON `r`.`user_id` = `u`.`id`
WHERE `r`.`ticket_id` = ?
) UNION (
SELECT
`l`.`ticket_id`,
'logs' AS `table`,
`u`.`username`,
`l`.`action` AS `message`,
`l`.`created_at`
FROM `logs` AS `l`
LEFT JOIN `users` AS `u`
ON `l`.`user_id` = `u`.`id`
WHERE `l`.ticket_id` = ?
)
ORDER BY `created_at` DESC
It's pretty self-explanatory: do the two queries, returning the same columns, UNION them and then sort that result set in MySQL. Hopefully it (or something similar, as I've had to guess your database structure) will work for you.
As for translating that into a Laravel DB::-style query, I guess that's up to you.

Categories