Laravel Unique returns only one record - unique

I have a jobs table and operators table.
One operator can have several job records on the jobs table, while a job can only have one operator.
Now i want to get the record of the latest job of all operators with no duplication.
Here's what i used
$availableOperators = DB::table('operator')
->join('job','operator.OperatorId', '=', 'job.OperatorId')
->where('operator.available',1)
->orderBy('job.JobId','desc')
->get()
->unique('job.OperatorId');
Without the unique query, i am able to see all the records that satisfy the condition but on including it, i'm getting only the first record it finds and none other
Please advise on what i'm doing wrong

Apparently, unique would always give only one record, I solved it by using groupBy instead.
$availableOperators = DB::table('operator')
->join('job','operator.OperatorId', '=', 'job.OperatorId')
->where('operator.available',1)
->orderBy('job.JobId','desc')
->groupBy('job.OperatorId')
->get();

Related

Yii2 Dynamic Relational Query Junction with Sort uses 2 queries instead of a JOIN, why?

I'm working with Yii2 Relational Database / Active Query Models and I ran into an issue trying to use the magic method getModelName() with $this->hasMany()->viaTable() to set the relation while trying to sort by a sort column in my junction table.
First I tried to just add my ->orderBy() clause to the main query:
return $this->hasMany(Category::class,
['id' => 'categoryId'])
->viaTable('{{kits_x_categories}}',
['kitId' => 'id'])
->orderBy('{{kits_x_categories}}.sort asc');
That didn't work as expected and upon further digging I found out that this results in two separate queries, the first one selects my category Ids into an array, then uses said array for a WHERE IN() clause in the main (2nd) query to get the actual models that are related.
My first thought was to use the 3rd function($query) {} callback parameter of the ->viaTable() call and putting my $query->orderBy() clause on there:
return $this->hasMany(Category::class,
['id' => 'categoryId'])
->viaTable('{{kits_x_categories}}',
['kitId' => 'id'],
function($query) {
return $query->orderBy('{{kits_x_categories}}.sort asc');
}
);
However, all that did was return the category ID's in my desired order but ultimately had no effect on the main query that does the IN() condition with said ids since the order of the ids in the IN() condition have no effect on anything.
Finally, I ended up with this which lets it do what it wants, but then forces in my join to the main query with the IN() condition so that I can have the main query sort by my junction table sort column. This works as desired:
return $this->hasMany(Category::class,
['id' => 'categoryId'])
->viaTable('{{kits_x_categories}}',
['kitId' => 'id'])
->leftJoin('{{kits_x_categories}}', '{{kits_x_categories}}.categoryId = {{categories}}.id')
->where(['{{kits_x_categories}}.kitId' => $this->id])
->orderBy('{{kits_x_categories}}.sort asc');
This results in 2 queries.
First the query gets the category ids from the join table:
SELECT * FROM `kits_x_categories` WHERE `kitId`='49';
Then the main query with the IN() condition and my forced join for sort:
SELECT `categories`.* FROM `categories`
LEFT JOIN `kits_x_categories` ON `kits_x_categories`.categoryId = `categories`.id
WHERE (`kits_x_categories`.`kitId`='49') AND (`categories`.`id` IN ('11', '7', '9'))
ORDER BY `kits_x_categories`.`sort`
So here is my actual question... This seems largely inefficient to me but I am by no means a database/SQL god so maybe I just don't understand fully. What I want is to understand.
Why does Yii do this? What is the point of making one query to get the IDs first, then making another query to get the objects based on the ids of the relation? Wouldn't it be more efficient to just do a regular join here? Then, in my opinion, sorting by a junction sort column would be intuitive rather than counter-intuitive.
The only thing I can think of is has to do with the lazy vs eager loading of data, maybe in lazy in only gets the IDs first then when it needs to load the data it pulls the actual data using IN()? If I used joinWith() instead of viaTable() would that make any difference here? I didn't dig into this as I literally just thought of that as I was typing this.
Lastly, In this scenario, There is only going to be a few categories for each kit so efficiency is not a big deal but I'm curious are there any performance implications in my working solution if I were to use this in the future on a different model set that could have thousands+ of relations?
Yii 2 does that:
To support lazy loading.
To support cross-database relations such as MySQL -> Redis.
To reduce number of edge-cases significantly so internal AR code becomes less complicated.
3rd party software is usually designed to get you started with databases. But then they fall apart when the app grows. This means that you need to learn the details of the underlying database in addition to the details of the layer.
Possibly this specific issue can be solved by improving the indexes on the many-to-many table with the tips here: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
This, of course, depends on whether the layer lets you tweak the schema that it created for you.
If there is a way to write "raw" SQL, that might let you get rid of the 2-step process, but you still need to improve the indexes on that table.

Avoid column ambiguity on join by setting default table with laravel's query builder

I want to order a query (from revenues table) by relationship's column ('orders.number'). One order has many revenues. The problem is that both revenues and orders share a common column (description) which causes ambiguity on filtering by where(). I know I can specify the tables when filtering, but the issue here is that I'm using a global scope which orders the query by preset columns in a config file and description is one of them. I couldn't previously know the table name and sending it as a parameter to the function seems like an overkill for me.
$revenues = App\Revenue::
with('order.client', 'order.place')
->sessionSearch('revenues')
->orderBy('created_at', 'desc')
->join('orders', 'orders.id', '=', 'revenues.order_id')
->select('revenues.*', 'orders.number as order_number')
->orderBy('order_number', 'desc')
->paginate(perPage());
I tried dynamically adding the table name in the sessionSearch() method, but I couldn't access it via the passed Builder instance, becuase it was protected.
I also thought that by performing a leftJoin mysql would know which my main table is and presumably target its columns, but ambiguity is still an issue.
Is there a way I can set a favorable table by default in my sql settings so that no ambiguity is caused? Basically I only need the number from the orders table, but ambiguity error is still being thrown.
Thanks in advance for any help!

SQL row order in query

If you are given a query is there a way to determine if you can always get a return in a particular order? Like if you had to return by SSN or name or price,can you guarantee a way in MySQL to get a query to return by SSN?
can you guarantee a way in MySQL to get a query to return by SSN?
...
ORDER BY ssn
That's the only way.
There are many people that try to be clever, and try to get a database engine to return rows in a certain order without specifying an ORDER BY clause, as if that would somehow optimize something. Don't! Just don't! That's just a recipe for disaster.

Flask-SQLAlchemy different record count for .count() and .all()

In SQLAlchemy, ModelName.query.filter_by(field_name=value).count() returns correct record count, but ModelName.query.filter_by(field_name=value).all() only returns a single record. Doing a db.session.execute("SELECT * FROM table_name WHERE field_name = 'value'") works fine. Has anybody faced a similar problem? Does anyone have any idea what could possibly be wrong. Any pointers will help.
Information that might be helpful
I am using MS SQL Server 2008 R2 and accessing it using FreeTDS/pyodbc. I do not control the database and can not change it.
Thanks in advance.
I think I may have fallen in the same problem. My query do multiple Joins, than the raw result can bring back multiple rows of the same primary key, each row is counted by .count(), however when you call .all() a distinct is applied on the primary key and only unique rows are fetched, than the number of records on .all() list is different from .count().
This should be equal:
query.distinct().count() == query.all()
Best regards
The function all() return a list and count() return a number...

Index of a record in a sorted relations

Given I have a sorted relation (perhaps done by
SELECT id
FROM model
WHERE type = 'a'
ORDER BY name`
...), now I want to quickly get the index of a specific record e.g record id#15003.
How should I do it in MySql [I'm a Rails developer]?
Assuming by index you mean row number. That is, if the results come back '1, 7, 9,...' then the "index of 9" is 3, it is the third row.
You want what are variously called "Window functions" or "statistical functions" like row_number().
MySQL doesn't have them. Sorry.
However, though I'm not a RAILS developer, I have to assume you can get results in an array and search the array and return an index number?
EDIT: Based on your comment to Brad's answer, if you are doing this for the sake of paginating results, then look at the LIMIT and OFFSET. http://dev.mysql.com/doc/refman/5.0/en/select.html
Are you looking for something such as this: http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/
I believe this is going to require you to select all results up to your desired result. So, if your record is at index 15003, you must select records 1-15003. Obviously this is not efficient or scalable... Perhaps there is a better way to approach the problem? Why do you need the index anyway? Why not place a more restrictive WHERE condition on the original SQL?