I have 3 models. Table1 belongs to Table2, and Table2 belongs to Table3.
I want to get an ActiveRecord::Relation that includes all of the fields from all 3 tables, including nulls (outer joining to get all of Table1), with a WHERE clause on Table1 and an order by a column in Table3.
What I want in SQL is:
SELECT * FROM Table1 LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id
LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id
WHERE Table1.column1 = "example"
ORDER BY Table3.table3_column
However, I have been trying for hours now to do this in rails and getting nowhere. Is it possible?
#records = Table1.joins(:table2).joins(:table3).where(:column1 => "example").order("table3_column")
(For example), gets me nowhere because it is looking for an association between Table1 and Table3, which doesn't exist other than through Table2. I need to join once, then join on top of that. Not to mention that is an inner join. I've tried of the form:
#records = Table1.joins("LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id")
But I get nil from that.
Thanks for any help with this.
Try find_by_sql
Table1.find_by_sql("SELECT * FROM Table1
LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id
LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id
WHERE Table1.column1 = "example"
ORDER BY Table3.table3_column")
refer find by sql
Related
I have three tables and I have to write one query to update table 1 row from table 3 and the only matching columns I have is in table 2.
Table 1 which has incorrect data:
Table 3 has the correct data:
I did try to write a query and execute it but it gives me an error saying there are too many rows too select which is true I do have many rows to correct but it still wouldn't correct. What do you think I should do. This is my query so far.
UPDATE Table1
SET Table1.Number = (SELECT Table3.Number
FROM Table2
FULL OUTER JOIN Table1 ON Table1.ID = Table2.ID
FULL OUTER JOIN Table3 ON Table3.Signin = Table2.Signin
WHERE (Table2.ID = Table1.ID)
AND (Table1.Number = 'xxx'))
WHERE (Tale1.Number = 'xxx')
In Where clause of JOIN query need to modify as multiple records are generating by inappropriate condition.Try to use Table3 components instead of using Table1 in joining query where clause.
UPDATE Table1
SET Table1.NUMBER = (SELECT table3.NUMBER FROM Table1 FULL OUTER JOIN Table2
ON Table1.ID = Table2.ID
FULL OUTER JOIN Table3
ON Table2.SIGNIN = Table3.SIGNIN
WHERE Table3.SIGNIN = 100) // This is the point where you need to modify your code
WHERE Table1.ID = 1;
ONLINE DEMO HERE
It actually worked after I removed this line from my query.
FULL OUTER JOIN Table1 ON table1.ID = Table2.ID
Thanks for the help.
You are fairly close. When doing the update though unless you are wanting to clear value for t1.number when a record is not matched in t3, you will want to use INNER JOIN. FULL OUTER JOIN would mean you are trying to update rows in t1 that don't exist but a LEFT JOIN you would update t1.number to NULL if a record in t3 doesn't exist.
UPDATE t1
SET t1.Number = t3.Number
FROM
Table1 t1
INNER JOIN Table2 t2
ON t1.Id = t2.Id
INNER JOIN Table3 t3
ON t2.Signin = t.3.Signin
WHERE
t1.number <> t3.number
--Or if you have nulls something like
--ISNULL(t1.number,'xxx') <> ISNULL(t3.number,'xxx')
-- if you only want to update when t1.number = 'xxx' then
--t1.number = 'xxx'
t1,t2,t3 are table aliases that I created by adding the alias after table name. By using join syntax rather than a sub select you simplify your were conditions. In sql-sever if more than 1 record in t2 & t3 match it will select one row randomly in the case of a one to many relationship. If you want a specific record when not one to one relation you can use window functions and common table expressions (cte) to limit t3 to the exact record you want to use.
OK so my question is: There a difference in record count depending on where the AND statement is positioned within my query. For instance, if I have several INNER JOINS and a couple LEFT Joins and at the very end of my query if I place all my AND statements the record count is different then if I place my AND statement right below the matching JOIN table. Since the AND statement specifies the table, why would it matter where its placed within the query?
Example 1:
FROM table (nolock)
INNER JOIN table2 (nolock) ON Table.ID = table2.ID
INNER JOIN table3 (nolock) ON table2.ID = table3.ID
LEFT JOIN table4 (nolock) ON table3.ID = table4.ID
where table.vendor = 1234
AND table.Active = 1
And table2.Active = 1
And table3.Active = 1
and table4.Active = 1
and table3.Name LIKE 'someName'
Example 2:
FROM table (nolock)
INNER JOIN table2 (nolock) ON Table.ID = table2.ID
And table2.Active = 1
INNER JOIN table3 (nolock) ON table2.ID = table3.ID
And table3.Active = 1
and table3.Name LIKE 'someName'
LEFT JOIN table4 (nolock) ON table3.ID = table4.ID
where table.vendor = 1234
and table4.Active = 1
AND table.Active = 1
When using INNER JOIN it makes no difference whether the criteria accompanies the JOIN or if it's in the WHERE clause, however with LEFT JOIN adding join criteria doesn't filter out non-joining records, but that criteria in the WHERE clause will exclude non-joining records. In your case WHERE table4.Active = 1 excludes non-joining records from table4, but moving that criteria to the JOIN will not exclude those records.
Here is a simple demonstration: SQL Fiddle
Note: I've made the assumption that your sample code isn't quite right and that this is the problem based on your description.
I have a mapping table referring to ids from two different tables. I would like to select the mapping table with each id being replaced by another field in the respective table.
To be a little more explicit: there are three tables with two columns each:
Table1 has a id (the primary key) and field1
Table2 has a id (the primary key) and field2
Table3 (the mapping table) has fields Table1_id (which takes values in Table1.id) and Table2_id (which takes values in Table2.id)
What I want is to get the content of Table3 with Table1.field1 and Table2.field2 as columns.
I know how to replace one of the columns in the mapping table with another column of one of the other tables, by using a inner join:
SELECT Table1.field1, Table3.Table2_id
FROM Table1
INNER JOIN Table3
ON Table1.id=Table3.Table1_id;
however I don't know how to do basically the same thing with both columns.
If i understood correctly you are trying to get field1 from Table1 and field2 from table 2. If so you just need to join the three tables
SELECT a.field1, c.field2
FROM Table1 a
INNER JOIN Table3 b
ON a.id=b.Table1_id
INNER JOIN Table2 c
ON b.Table2_id = c.id
Do another join.
SELECT Table1.field1, Table2.field
FROM Table1
INNER JOIN Table3
ON Table1.id = Table3.Table1_id
INNER JOIN Table 2
ON Table2.id = table3.table2_id;
You just need to join all three tables; something like
SELECT Table1.Field1, Table2.Field2
FROM Table3
JOIN Table1 ON Table1.Id = Table3.Table1_id
JOIN Table2 ON Table2.Id = Table3.Table2_id
I do not know if I understood correctly what you want to achieve but this should get you results from both tables joined by thier keys
SELECT Table1.field1, Table2.field2
FROM Table1
INNER JOIN Table3 ON Table1.id = Table3.Table1_id;
INNER JOIN Table2 ON Table2.id = Table3.Table2_id;
I'm trying to execute a query that looks similar to this:
SELECT <columns> FROM table1
INNER JOIN table2 ON table1.id = table2.table1_id
INNER JOIN table3 ON table1.id = table3.table1_id
WHERE table3.column1 != 'foo' AND <other_conditions>
LIMIT 1;
The thing is--I want the query to return a result regardless of whether the record in table3 exists or not. That is--if the record in table3 is present, I want to check whether that record has a certain column value. If the record in table3 doesn't exist, I want the query to assume that the condition is TRUE.
Any pointers?
You use a left join on the table. If no corresponding record exists, the value from the table will be null, so you can use coalesce to get a value that you can compare to the string:
SELECT <columns> FROM table1
INNER JOIN table2 ON table1.id = table2.table1_id
LEFT JOIN table3 ON table1.id = table3.table1_id
WHERE COALESCE(table3.column1, '') != 'foo' AND <other_conditions>
LIMIT 1
You've come to a point where you noticed that there is a difference between WHERE conditions and JOIN conditions.
SELECT
<columns>
FROM
table1
INNER JOIN table2 ON table2.table1_id = table1.id
LEFT JOIN table3 ON table3.table1_id = table1.id AND table3.column1 <> 'foo'
WHERE
<other_conditions>
LIMIT 1;
You need to use an outer join to include table3 instead of an inner join.
I have a query with inner join to another table, with this I want also include records which are contained in another column.
Example:
select name, address from table1
inner join table2 on table1.id = table2.id
With this, I want to also include rows which are having table1.recno = (1,2,4).
How could I write query for that?
One option I know is to use the IN keyword instead of the first table join. But our client doesn't want to use the IN keyword.
Use a left join and then use the WHERE clause to filter out the rows that you need.
select name, address
from table1
left join table2 on table1.id = table2.id
where
table2.id IS NOT NULL OR table1.ID In (1,2,4)
Or if you want to avoid an innocuous IN for silly reasons, use:
select name, address
from table1
left join table2 on table1.id = table2.id
where
table2.id IS NOT NULL
OR table1.ID = 1
OR table1.ID = 2
OR table1.ID = 4