Rails way of writing this Mysql query - mysql

I have a Mysql query which is this:
actors_to_delete = find_by_sql("SELECT * FROM `dvd_role` a
LEFT JOIN `dvd_actor2role` b ON a.id = b.`roleId`
LEFT JOIN `dvd_actor` c ON b.`actorId` = c.`id`
WHERE role LIKE '%uncredited%'
GROUP BY c.id")
I've written it the Railsy way like this:
actors_to_delete = Role.joins("LEFT JOIN `dvd_actor2role` ON dvd_role.id = dvd_actor2role.`roleId`").joins("LEFT JOIN `dvd_actor` ON dvd_actor2role.`actorId` = dvd_actor.`id`").where("dvd_role.role LIKE '%uncredited%'").group("dvd_actor.id")
What I'm wondering (apart from the fact that what is really the difference between these 2 queries, they both do the same thing, so why favour the Railsy way over the more straightforward sql way?) is how do I write it with the relations that are already established in Rails.
If I try do something like this:
Actor.actor2role.role.where("role LIKE ?", '%uncredited%')
I'll get undefined method actor2role because, even though the relationships have been established in Rails, they work for an instance of Actor, not the model itself.
So, in conclusion, just wondering what the best way to do it is. Coming from PHP and Mysql I tend to write a lot of these things out the sql way and am trying to change my evil ways :)
Edit
I also have another problem and that's the fact that in the sql query I get all the info from all 3 tables, the Rails way gives me only the dvd_role table for some reason.
How can I get the data from the other 2 table as well?
I was able to do the latter by adding .select("*") in the beginning. Is this the appropriate way:
actors_to_delete = Role.select("*").joins("LEFT JOIN `dvd_actor2role` ON dvd_role.id = dvd_actor2role.`roleId`").joins("LEFT JOIN `dvd_actor` ON dvd_actor2role.`actorId` = dvd_actor.`id`").where("dvd_role.role LIKE '%uncredited%'").group("dvd_actor.id")

Related

When can I say that it's the best-optimized query?

I tried to optimize a query, but it still a tad bit slow. Here, EXPLAIN statement data for reference. Also adding an execution and evaluation cost information JSON. Can you tell me if I can improve something? Or it's the best that I can do.
Exaplain.json
EDIT
What I really want to know is, a way to know that the query is fully optimized and I should start looking somewhere else.
Anyways, please tell me for this query and I will learn something more. Adding the query and a diagram of the table structure.
SELECT o.object, b.baseline, s.testType, ut.suite,
JSON_EXTRACT(ut.failTestsData, '$.failButBaselinePassesTests[*]',
'$.baselineDataNotAvailableTests[*]',
'$.failDifferentThanBaselineTests[*]') AS failTests FROM objects as o
LEFT JOIN baselines as b ON b.baselineID = o.baselineID
LEFT JOIN instances AS i ON o.objectID = i.objectID
LEFT JOIN buildOSs as os ON i.osID = os.osID
LEFT JOIN unittestsdetails AS ut ON ut.instanceID = i.instanceID
LEFT JOIN suites AS s ON s.suiteID = ut.suiteID
WHERE o.objectID IN ( 20836, 20210, 20201, 20202, 20370, 21138, 20731,
22242, 21168, 21476, 23384, 22043, 20548, 20289, 20777, 21324, 20545,
20682, 20266, 21184, 21202, 20741, 20918, 20261, 20516, 20291, 20619,
21438, 20351, 22047, 20264, 20265, 21181, 20988, 20842, 21429, 20643,
20570, 20775, 21904, 20923........... )
If you need something else please let me know.
a way to know that the query is fully optimized and I should start looking somewhere else
This doesn't really exist, for a simple reason : if your query is a "bit" complex, depending on the data in your table, what is "fully optimized" may turn to be a pretty bad choice.
Working on a single line vs some thousand of thousand is not the same.
For less complex query, I'll say : if every WHERE and JOIN clause use an index, then you're probably as close as "optimized" you can (maybe function based index and different kind of index, but that's it).
Looking at your query is seem you're already done ;)

phpmyadmin SQL query multiple tables

I have two tables.
(1) compressors
(2) crankcase_heaters
I'm trying to create a SQL query to do:
Select the compressor.VOLTAGE and compressor.WATT of each compressor.PART_NUMBER
Find the crankcase_heater.PARTNO that has the same voltage and watts.
Add that value into a new field on the compressor table called "CRANKHTR"
Essentially this query will reproduce my compressors table but will have another 'column' called "CRANKHTR".
I'm completely lost on where to even start with this. I tried using the phpmyadmin SQL Query builder but i have no idea where to begin.
Without seeing the exact data structure, it sounds like you need a simple INNER JOIN:
SELECT
`cp`.`VOLTAGE`,
`cp`.`WATT`,
`ch`.`PARTNO` as CRANKHTR
FROM
`compressor` cp
INNER JOIN `crankcase_heaters` ch ON ch.VOLTAGE = cp.VOLTAGE AND ch.WATT = cp.WATT

MultipleObjectsReturned error in django admin - but there is no duplication in database

I'm having a problem in the Django admin. I'm using version 1.5.5
I have a Booth model which has a foreign key to my AreaLayout model, which then goes back through another few models with foreign and many2many keys. My model code can be seen on pastebin. The initial indication of the problem in admin is that AreaLayouts are being duplicated in the select dropdown in Booth admin. The MultipleObjectsReturned error (traceback) is being raised when I then try to save a new booth. I was able to trace this back to the SQL query that django is creating to grab the AreaLayout list:
SELECT `venue_arealayout`.`id`, `venue_arealayout`.`name`, `venue_arealayout`.`description`, `venue_arealayout`.`area_id`, `venue_arealayout`.`additional_notes`
FROM `venue_arealayout`
INNER JOIN `venue_area` ON (`venue_arealayout`.`area_id` = `venue_area`.`id`)
INNER JOIN `venue_venue` ON (`venue_area`.`venue_id` = `venue_venue`.`id`)
INNER JOIN `venue_venue_venue_type` ON (`venue_venue`.`id` = `venue_venue_venue_type`.`venue_id`)
INNER JOIN `venue_venuetype` ON (`venue_venue_venue_type`.`venuetype_id` = `venue_venuetype`.`id`)
WHERE (`venue_arealayout`.`id` = 66 )
This query produces a duplicate in MySQL when I run it there. Removing the final 2 JOINs results in a single result being returned (which is the desired result), whereas removing only the last join still results in duplication.
I tried running that query with SELECT * in place of selecting specific fields and the two results in that case are almost equal. The difference is that the venue in question has multiple venuetypes and I'm getting a result for each of those. Is there any way I can tell django not to include those joins for these queries, or is there a way I can get distinct results as far as AreaLayouts go?
I think you're being caught by the bug reported in ticket 11707. One of the comments mentions that it can cause a MultipleObjectsReturned exception.
All I can suggest is that you stop using limit_choices_to. Your models are fairly complex, so I can't immediately see which one is causing the problem.

CI active record style sql queries

I am new in Code Igniter and like its active record feature now is there any useful steps or tips or any guidness how do i convert my pervoiusly written simple SQL Queries in CI style like this is my perviouly written simple query
SELECT *
FROM hs_albums
WHERE id NOT IN (SELECT album_id
FROM hs_delete_albums
WHERE user_id = 72
AND del_type = 1)
AND ( created = 72
OR club_id IN (SELECT cbs.id
FROM hs_clubs cbs
INNER JOIN hs_club_permissions cbp
ON cbs.id = cbp.club_id
WHERE cbp.user_id = 72
AND cbp.status = 2)
OR group_id IN (SELECT gps.id
FROM hs_groups gps
INNER JOIN hs_group_permissions grp
ON gps.id = grp.group_id
WHERE grp.user_id = 72
AND grp.status = 2)
OR comp_id IN (SELECT cmp.id
FROM hs_companies cmp
INNER JOIN hs_comp_permissions comp
ON cmp.id = comp.comp_id
WHERE comp.user_id = 72
AND comp.status = 2) )
The short answer is: You don't.
CodeIgniter's Active Record implementation is basically a layer on top of SQL that makes writing queries easier by:
Automatically escaping values
Automatically generating the appropriate query syntax for the database, so that the application can be more easily ported between databases (for instance, if you didn't use Active Record to write a query, and then wanted to move from MySQL to PostgreSQL, then you might well need to rewrite the query to make it work with PostgreSQL)
Providing a syntax for queries in PHP directly, thus avoiding the context switching between PHP and SQL.
However, it can't do everything SQL can do, and while I would always try to use ActiveRecord where possible, there comes a point where you're better off forgetting about using it and just using $this->db->query() to write your query directly. In this case, as mamdouh alramadan has said, CodeIgniter doesn't support subqueries so you can't replicate this query using ActiveRecord anyway.
The thing to remember is that ActiveRecord is a tool, not a requirement. If you're using CodeIgniter and aren't using an ORM instead, you should use it for the reasons mentioned above. However, once it starts getting in the way, you should consider whether it would be better practice to write your query manually instead.

Linq2sql Optimizing Left join to get items that exist in only in 1 container

I want to get items from one container that don't exist in another. One container is IEnumerable, and another is an entity in DB. For example
IEnumberable<int> ids = new List<int>();
ids.Add(1);
ids.Add(2);
ids.Add(3);
using (MyObjectContext ctx = new MyObjectContext())
{
var filtered_ids = ids.Except(from u in ctx.Users select u.id);
}
This approach works, but I realized that underlying sql is something like SELECT id FROM [Users]. That is not what I want. Changing it to
var filtered_ids = ids.Except(from u in ctx.Users
where ids.Contains(u.id)
select u.id);
improves underlying query and adds WHERE [id] IN (...) which seems a way better.
I have 2 questions:
Is it possible to improve performance any further for this query?
As far as I remember there is a limit on how many parameters can be in IN . Will my current query work if I exceed the limit (which is not very likely to happen, but it's better to be prepare) ?
That query should be fine, provided proper indexes/primary keys are in place.
The upper limit on sql parameters accepted by sql server is around 2100. If you exceed the limit, you will be met with a sql exception instead of results.