ActiveJDBC #BelongsTo JOIN? Cached? - activejdbc

Let's say I have a model M1.java that contains
#BelongsTo(foreignKeyName = "m2_id", parent = M2.class)
and then after loading M1 I do
M2 myM2 = myM1.parent(M2.class)
I suppose an extra query is made to fetch the M2 object (similar to Hibernate FetchType.LAZY), how can we force a JOIN on the first query (that loads M1 object(s))?
In the case it's not possible, or that I don't want to join in certain cases, will every call to parent(M2.class) re-run the query to load M2 or will it be cached in the M1 object after the first "fetch"?
Thanks.
EDIT:
I found this page http://javalite.io/lazy_and_eager that explains that the parent won't be cached unless I use the include() method.
The problem is when I use it I see in the logs the query to select the parents with one query BUT I still see the extra queries to load them 1 by 1 again! So it's not O(2) instead of O(n+1), but O(n+2)!
...
// Both test tables contain 1 row
List<M1> myM1s = M1.where(query, params).include(M2.class);
...
// Duplicating 3 times the print statement for test purpose
System.out.println(myM1s.get(0).parent(M2.class));
System.out.println(myM1s.get(0).parent(M2.class));
System.out.println(myM1s.get(0).parent(M2.class));
...
Logs
Query: "SELECT * FROM m1 WHERE...", with parameters:...
Query: "SELECT * FROM m2 WHERE id IN (1)"
Query: "SELECT * FROM m2 WHERE id = ?", with parameters: <1>
[print statement]
Query: "SELECT * FROM m2 WHERE id = ?", with parameters: <1>
[print statement]
Query: "SELECT * FROM m2 WHERE id = ?", with parameters: <1>
[print statement]
What is going on?

I could not replicate your experience. Here is the test that is identical to your code: https://github.com/javalite/activejdbc/blob/master/activejdbc/src/test/java/org/javalite/activejdbc/IncludesTest.java#L32
Line 38 checks that the two references point to the same exact object. Also, the test prints this:
[main] INFO org.javalite.activejdbc.LazyList - Query: "SELECT * FROM addresses WHERE city = ? ORDER BY id", with parameters: <Springfield>, took: 11 milliseconds
[main] INFO org.javalite.activejdbc.LazyList - Query: "SELECT * FROM users WHERE id IN (?, ?)", with parameters: <1>, <2>, took: 9 milliseconds
As you can see, the framework works as expected. You can clone sources and run in your environment to validate this.
Something must be wrong with your environment?

Related

sqlite eval INNER JOIN on self duplicates v(*) entries

I have an SQLite database db and a view pending_nodes. To find pending_subnet - pending nodes whose upstream is also a pending node - I've prepared this statement:
db eval {
SELECT * FROM pending_nodes AS left
INNER JOIN pending_nodes AS right ON left.process=right.upstream} v {
parray v
# do stuff...
}
To my surprise parray gives me this result:
v(*) = node process type upstream node process type upstream
v(node) = 2
v(process) = 6
v(type) = reference
v(upstream) = 5
The printed data is as expected, but the v(*) list is duplicated. Looks weird and suspect I've done something wrong.
Q: What did I do wrong?
From #JoakimDanielson comment, selecting * from just one of tables (right) gives expected results:
SELECT right.* FROM pending_nodes AS left
INNER JOIN pending_nodes AS right ON left.process=right.upstream

Complex SQL postgres query into ActiveRecord notation?

Hoping an ActiveRecord wizard can help me determine if this kind of query can be done with a AR statement, i.e. without executing the raw SQL or diving into Arel?
I'm getting close but can't seem to figure out how to add the subquery in. I'm on Rails 5.1.1.
SELECT s.id as stock_id, s.count, adjustments.count as
adjustment_count, adjustments.reason as adjustment_reason
FROM
(SELECT * FROM stocks WHERE inventory_id = 6) AS s
LEFT JOIN adjustments
ON (s.id = adjustments.stock_id AND adjustments.reason='run_use')
The end result should be all Stock that have inventory id 6 with the extra columns showing what Adjustment was made to them, if they exist.
If I run the RAW SQL in Navicat I get this result, which is what I'm trying to get via ActiveRecord:
This gets me close, but it just produces stock_ids 11 and 10:
Stock.where(inventory:6)
.left_joins(:adjustments)
.where("adjustments.reason = 'run_use'")
One of these should work for you:
Stock.eager_load(:adjustments)
.where("adjustments.reason = ? OR stocks.inventory_id = ?", "run_use", 6)
or
Stock.eager_load(:adjustments)
.where(adjustments: { reason: "run_use" }, inventory_id = 6)
Hm. It seems you're trying to say:
Give me all Stock that belong to Inventory with id = 6 that also have Adjustments with a reason of 'run use'.
How about something like:
Stock.
where(inventory_id: 6).
joins(:adjustments).
where(adjustments: { reason: 'run_use' })
from the Guides

Pentaho database lookup to fetch data

I have a database table, "FTTAGS" which has below 3 fields.
FTDATA
INST
KEY
FTDATA has value as shown below.
19,40,92,27456,1,9,6,7,121,6,7,5,01,24001,523247,19,005,12,6,7,222,2,98,1241222514,0,3933602,2745,8,1,1,1,1,1,1,1,16,6,6,6,335,19,40,92,2745,1,9,6,7,2745,8,1,1,1,1,1,1,1,16,6,6,6,335,98,5,01,204198,192,9,47,47,20,5,12,6,7,12,6,7
INST has value
"Frequecy -21 0x337811 gf.2241"
I need to search for "3933602" and fetch corresponding KEY .
I am not able to get any option in database lookup to do the same. Please help. I tried running a sql query using "Execute sql script". But it is not returning any values.
I tried below in execute sql script. But it did not return the output value.
select KEY from FTTAGS where INSTR(FTDATA,'?') > 0 AND INST like '?';
By using Database join step. You can achieve the goal. Let us see how to achieve these goal.
SQL: select * from FTTAGS where FTDATA = 3933602;
Take Database join step to canvas.
SQL: select * from FTTAGS where FTDATA = ?;
Follow below image for clear clarification.
If you want both results. You can follow below image.
Database join step:
SQL: select * from FTTAGS
Filter step:
<field> => FTDATA
operateor => =
<value> => 3933602
=> Red mark dummy step gives not satisfied result.
=> green tick mark dummy step gives satisfied result.
I think these information will useful to you.
Database join_1 step:
SQL: select * from FTTAGS where FTDATA = 3933602
Database join_2 step:
SQL: select * from FTTAGS where FTDATA <> 3933602
For clear clarification purpose you can see the below image
Thank you.

Rails 3 how to reduce queries

c = Conversation.joins(:messages).random
>> Conversation Load (8.1ms) SELECT `conversations`.* FROM `conversations` INNER JOIN `messages` ON `messages`.`conversation_id` = `conversations`.`id` ORDER BY created_at DESC, RAND() LIMIT 1
Count:
c.messages.count
>> (5.7ms) SELECT COUNT(*) FROM `messages` WHERE `messages`.`conversation_id` = 74
Length:
c.messages.length
>> Message Load (1.2ms) SELECT `messages`.* FROM `messages` WHERE `messages`.`conversation_id` = 82
How to not perform additional queries above? I thought I have already joined messages for the random conversation using INNER JOIN, and yet a new query is performed to count those results?
The second issue is attempting to get all joined messages with a specific user_id:
u = User with id 27 # has messages in 'c' results above
c.messages.where('user_id = ?', u.id).all
>> Message Load (5.3ms) SELECT `messages`.* FROM `messages` WHERE `messages`.`conversation_id` = 82 AND (user_id = 27)
I used select to do this without additional queries:
c.messages.select { |msg| msg.user_id == u.id }
>> returns messages without query logged
I'd still appreciate how I might reduce or optimize these queries.
Try using includes instead of joins to avoid the n+1 problem.
Railscast #181 By Ryan Bates, http://railscasts.com/episodes/181-include-vs-joins?view=asciicast, explains the difference in an easy way.

Why does Rails generate a SQL query for an "include?" call in a view but not in the console?

In my app a Position has_many Questions. In my position edit view, I create a set of checkboxes by looping over an array of Questions and checking those that the current position already includes.
Looks like this:
- #questions.each do |question|
= check_box_tag :question_ids, question.id, #position.questions.include?(question), name: 'position[question_ids][]', id: "question_check_#{question.id}"
= label_tag "question_check_#{question.id}", question.text
I noticed loading this page took an unusually long time and my logs had these (I've snipped it for space):
LOG: duration: 827.370 ms statement: SELECT 1 FROM "questions" INNER JOIN "required_questions" ON "questions"."id" = "required_questions"."question_id" WHERE "required_questions"."position_id" IS NULL AND "questions"."id" = 1 ORDER BY account_id desc, "questions".id asc LIMIT 1
LOG: duration: 821.666 ms statement: SELECT 1 FROM "questions" INNER JOIN "required_questions" ON "questions"."id" = "required_questions"."question_id" WHERE "required_questions"."position_id" IS NULL AND "questions"."id" = 2 ORDER BY account_id desc, "questions".id asc LIMIT 1
LOG: duration: 713.379 ms statement: SELECT 1 FROM "questions" INNER JOIN "required_questions" ON "questions"."id" = "required_questions"."question_id" WHERE "required_questions"."position_id" IS NULL AND "questions"."id" = 3 ORDER BY account_id desc, "questions".id asc LIMIT 1
I tracked the problem to this code:
#position.questions.include?(question)
I thought this was a simple Array.include? check so I was surprised by my findings. I was also surprised when I fixed it by adding an explicit .to_a call:
#position.questions.to_a.include?(question)
I was surprised a third time when I tested the original code in the Rails console and no SQL query was generated.
At this point I'm just curious - why did my original code generate a SQL query for each iteration when the same code in Rails console (albeit without the iteration and inside Rails console) did not? Why didn't it just do an Array.include? check?
This happens because #position.questions is not an array. It's actually an ActiveRecord::Relation. The problem is that the console actually behaves differently from your server application.
For example, in your console position.questions returns an array. That is because the console is actually evaluating this expression as position.questions.all which is equivalent to position.questions.to_a. In your server application the to_a or all is not called until you actually use the query. This is a good thing because it means you can continue to build up a query and it will only actually get executed when it's called.
For instance:
query = #position.questions
query.first
query.last
Will actually generate two queries that return two records in your server application because the query variable will be assigned an ActiveRecord::Relation instead of an Array. In your console this will generate a single query, but the query will load all of the questions into an Array and assign that to query and then select the first and last elements.
The all, first, last, count and even include? keywords are all triggers that actually execute the query, so in your application when you call #position.questions.include? you are executing a single query on the #position.questions relation. Adding the to_a causes this query to be executed immediately.