Is it not possible to perform a left join in Rhomobile?
I have models PriceGroups, PriceLookup which have a 1-many relationship (ie. each PriceGroup and have many PriceLookup records).
I need to do a simple SQL Left Join so I have the required information from the PriceGroups Table
SELECT * FROM PriceLookup
LEFT JOIN PriceGroups ON PriceLookup.price_group_code=PriceGroups.code
I have added this to the price_lookup model:
belongs_to :price_group_code, 'PriceGroups'
The following is what I have tried in Rhomobile
PriceLookup.find_by_sql("SELECT *
FROM PriceLookup
LEFT JOIN PriceGroups on PriceLookup.price_group_code=PriceGroups.code")
But I get error:
Error: could not prepare statement: 1; Message: no such table: PriceGroups
I know I can do two selects and join them myself but this is a very crap way of doing it
You need to create the RhoMobile model as FixedSchema, not using the default PropertyBags.
Otherwise you don't have a real table in SQLite but you're using the special objectValues table that is implementing a Key-Value store:
http://docs.rhomobile.com/rhodes/rhom#fixed-schema
Example:
dbPT = ::Rho::RHO.get_src_db('PriceLookup')
sql = "SELECT * FROM PriceLookup LEFT JOIN PriceGroups ON PriceLookup.price_group_code=PriceGroups.code"
lines = dbPT.execute_sql(sql)
This could happen if the table PriceGroups hasn't been initialized (created) yet. Tables are created when the model class is loaded, if they don't exist.
For your case, simply call the model class, this will load it and create the table if necessary.
PriceGroups; #Only for create the table
PriceLookup.find_by_sql("SELECT * FROM PriceLookup LEFT JOIN PriceGroups on PriceLookup.price_group_code=PriceGroups.code")
Related
Is it possible to join the same table twice?
In our case we want:
polymorphic.left_joins(:course, step: :course)
Problem when polymorphic row has a type "Step" in such case associated course of step does not join
Why do you need to join it twice?
For example we have a Polymorphic model that belongs to either a Course model or a Step model. Step belongs_to course. We should join course or step with course. It means if Polymorphic row has type Course we join course.fields if type Step we need to join steps with course so we can have in one row polymorphic.fields + steps.fields + associated course.fields
⚙ We can join the same table twice manually using alias for table (t1)
⛄
sql = <<-SQL
LEFT JOIN courses
ON courses.id = polymorphicable_id
AND (polymorphicable_type = 'Course')
LEFT JOIN steps
ON steps.id = polymorphicable_id
AND (polymorphicable_type = 'Step')
LEFT JOIN courses AS t1
ON t1.id = steps.course_id
SQL
polymorphic.joins(sql)
I have a sql query that I'd like to optimize. I'm not the designer of the database, so I have no way of altering structure, indexes or stored procedures.
I have a table that consists of invoices (called faktura) and each invoice has a unique invoice id. If we have to cancel the invoice a secondary invoice is created in the same table but with a field ("modpartfakturaid") referring to the original invoice id.
Example of faktura table:
invoice 1: Id=152549, modpartfakturaid=null
invoice 2: Id=152592, modpartfakturaid=152549
We also have a table called "BHLFORLINIE" which consists of services rendered to the customer. Some of the services have already been invoiced and match a record in the invoice (FAKTURA) table.
What I'd like to do is get a list of all services that either does not have an invoice yet or does not have an invoice that's been cancelled.
What I'm doing now is this:
`SELECT
dbo.BHLFORLINIE.LeveringsDato AS treatmentDate,
dbo.PatientView.Navn AS patientName,
dbo.PatientView.CPRNR AS patientCPR
FROM
dbo.BHLFORLINIE
INNER JOIN dbo.BHLFORLOEB
ON dbo.BHLFORLOEB.BhlForloebID = dbo.BHLFORLINIE.BhlForloebID
INNER JOIN dbo.PatientView
ON dbo.PatientView.PersonID = dbo.BHLFORLOEB.PersonID
INNER JOIN dbo.HENVISNING
ON dbo.HENVISNING.BhlForloebID = dbo.BHLFORLOEB.BhlForloebID
LEFT JOIN dbo.FAKTURA
ON dbo.BHLFORLINIE.FakturaId = FAKTURA.FakturaId
WHERE
(dbo.BHLFORLINIE.LeveringsDato >= '2017-01-01' OR dbo.BHLFORLINIE.FakturaId IS NULL) AND
dbo.BHLFORLINIE.ProduktNr IN (110,111,112,113,8050,4001,4002,4003,4004,4005,4006,4007,4008,4009,6001,6002,6003,6004,6005,6006,6007,6008,7001,7002,7003,7004,7005,7006,7007,7008) AND
((dbo.FAKTURA.FakturaType = 0 AND
dbo.FAKTURA.FakturaID NOT IN (
SELECT FAKTURA.ModpartFakturaID FROM FAKTURA WHERE FAKTURA.ModpartFakturaID IS NOT NULL
)) OR
dbo.FAKTURA.FakturaType IS NULL)
GROUP BY
dbo.PatientView.CPRNR,
dbo.PatientView.Navn,
dbo.BHLFORLINIE.LeveringsDato`
Is there a smarter way of doing this? Right now the added the query performs three times slower because of the "not in" subquery.
Any help is much appreciated!
Peter
You can use an outer join and check for null values to find non matches
SELECT customer.name, invoice.id
FROM invoices i
INNER JOIN customer ON i.customerId = customer.customerId
LEFT OUTER JOIN invoices i2 ON i.invoiceId = i2.cancelInvoiceId
WHERE i2.invoiceId IS NULL
I want to expand this question.
order by foreign key in activerecord
I'm trying to order a set of records based on a value in a really large table.
When I use join, it brings all the "other" records data into the objects.. As join should..
#table users 30+ columns
#table bids 5 columns
record = Bid.find(:all,:joins=>:users, :order=>'users.ranking DESC' ).first
Now record holds 35 fields..
Is there a way to do this without the join?
Here's my thinking..
With the join I get this query
SELECT * FROM "bids"
left join users on runner_id = users.id
ORDER BY ranking LIMIT 1
Now I can add a select to the code so I don't get the full user table, but putting a select in a scope is dangerous IMHO.
When I write sql by hand.
SELECT * FROM bids
order by (select users.ranking from users where users.id = runner_id) DESC
limit 1
I believe this is a faster query, based on the "explain" it seems simpler.
More important than speed though is that the second method doesn't have the 30 extra fields.
If I build in a custom select inside the scope, it could explode other searches on the object if they too have custom selects (there can be only one)
What you would like to achieve in active record writing is something along
SELECT b.* from bids b inner join users u on u.id=b.user_id order by u.ranking desc
In active record i would write such as:
Bids.joins("inner join users u on bids.user_id=u.id").order("u.ranking desc")
I think it's the only to make a join without fetching all attributes from the user models.
When I do includes it left joins the table I want to filter on, but when I add pluck that join disappears. Is there any way to mix pluck and left join without manually typing the sql for 'left join'
Here's my case:
Select u.id
From users u
Left join profiles p on u.id=p.id
Left join admin_profiles a on u.id=a.uid
Where 2 in (p.prop, a.prop, u.prop)
Doing this is just loading all the values:
Users.includes(:AdminProfiles, :Profiles).where(...).map{ |a| a[:id] }
But when I do pluck instead of map, it doesn't left join the profile tables.
Your problem is that you're using includes which doesn't really do a join, instead it fires a second query after the first one to query for the associations, in your case you want them both to be actually joined, so for that replace includes(:something) with joins(:something) and every thing should work fine.
Replying to your comment, i'm gonna quote few parts from the rails guide about active record query interface
From the section Solution to N + 1 queries problem
clients = Client.includes(:address).limit(10)
clients.each do |client|
puts client.address.postcode
end
The above code will execute just 2 queries, as opposed to 11 queries in the previous case:
SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
as you can see, two queries, no joins at all.
From the section Specifying Conditions on Eager Loaded Associations link
Even though Active Record lets you specify conditions on the eager loaded associations just like joins, the recommended way is to use joins instead.
Then an example:
Article.includes(:comments).where(comments: { visible: true })
This would generate a query which contains a LEFT OUTER JOIN whereas the joins method would generate one using the INNER JOIN function instead.
SELECT "articles"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "articles" LEFT OUTER JOIN "comments" ON "comments"."article_id" = "articles"."id" WHERE (comments.visible = 1)
If there was no where condition, this would generate the normal set of two queries.
I am having four table i need to join all the four table in my rails model How can i do it
My Join sample schema is
select * from
(
select id,name from table1
)a
left join
(
select * from table2
)b
on a.id=b.user_id
left join
(
select * from table3
)c
on a.id=b.ord_id
left join
(
select * from table4
)d
on a.id=d.other_id
One of the best features of rails is that you don't have to worry much about writing these types of database setups. I think you would be very well served by going through the intro to ActiveRecord:
http://guides.rubyonrails.org/active_record_basics.html
ActiveRecord abstracts the SQL up one layer, so you're (in theory) not writing any database-specific code. It also allows you to conceptualize your database schema at a higher level, rather than simply doing left join, inner join, etc. See here for more info on the various associations:
http://guides.rubyonrails.org/association_basics.html