ActiveRecord Query with nested table - ruby-on-rails

I am trying to make next query with ActiveRecord and have no idea about how to achieve this SQL result without using find_by_sql call.
SELECT *
FROM table_x AS a,
(SELECT locator, max(day_parsed) AS max_day
FROM table_x
WHERE day_parsed BETWEEN params[:day_from] AND params[:day_to]
GROUP BY locator) AS b
WHERE a.locator = b.locator
AND a.day_parsed = b.max_day
Any idea?

For example, we have active record TableX and its table name is table_x, so the query will be:
from = params[:day_from]
to = params[:day_to]
TableX.joins("JOIN (
SELECT locator, max(day_parsed) AS max_day
FROM table_x
WHERE day_parsed BETWEEN #{from} AND #{to}
GROUP BY locator
) as b ON b.locator = table_x.locator")
.where("table_x.day_parsed = b.max_day")

Related

GROUP on a column + COUNT in Rails 6 + PostgreSQL

I have built a PosgtreSQL request that works well in my PG client tool, but don't work when transposed for Rails.
The request that works:
SELECT
usr_drinks.optimized_all
COUNT(usr_drinks.optimized_all),
FROM
usr_seasons
INNER JOIN usr_drinks ON usr_drinks.id = usr_seasons.drink_id
INNER JOIN usr_properties ON usr_properties.id = usr_drinks.property_id
AND usr_properties.winery_id = 526
INNER JOIN msr_wineries ON msr_wineries.id = usr_properties.winery_id
INNER JOIN usr_photos ON usr_photos.season_id = usr_seasons.id
AND(usr_photos.verified_kind = 1
OR usr_photos.verified_kind = 0)
AND usr_photos.verified_at IS NOT NULL
WHERE
usr_drinks.optimized_at IS NOT NULL
AND usr_drinks.verified_at IS NULL
AND NOT EXISTS (
SELECT
NULL
FROM
msr_references
WHERE
msr_references.winery_id = msr_wineries.id
AND msr_references.verified_at IS NOT NULL)
GROUP BY
usr_drinks.optimized_all
HAVING COUNT(usr_drinks.optimized_all) > 5;
Now, In rails (I don't write the WHERE and JOIN there to clarify the request):
#record_with_minimum_drinks = Season.group("usr_drinks.optimized_all").
select("usr_drinks.optimized_all, COUNT(usr_drinks.optimized_all)").
where(where).
joins(joins).
having("COUNT(usr_drinks.optimized_all) > ?", #split_minimum_drinks).
first
But I obtain the classical error:
PG::GroupingError: ERROR: column "usr_seasons.id" must appear in the
GROUP BY clause
What did I miss ?
Thanks
ActiveRecord::FinderMethods#first adds sort by and limit to the query, which obviously will interfere with your request.

select all records from left table that do not exist in right table

I am working on sql server I have two tables and I need to return records from the left table which are not found in the right table for that I am using left join like below query,
select #MID=MID,#MName=Name,#PID=PID,#PName=PName,#DID=DID from #CompanyDataInfo where id=#MCount
insert into #temp SELECT Top(1) f.Name,f.PID,f.PName,v.* FROM #CompanyDataInfo f
left join Employee v on v.Id=f.ID and v.DID=f.DID
where v.Id =#MID and v.DId = #DId and v.PId = #PId and v.CId =#CId and DATE_TIME between DATEADD(minute,-555,GETDATE()) and GETDATE() order by DATE_TIME desc
Result should be all rows from #CompanyDataInfo table while no record found in Employee table for related ID, I googled and use "v.Id is null" but not getting expected result
Is there any solution greatly appriciable
Thanks In advance
Your query is not using left join in correct way. You are using your right table reference in where clause. I try to correct it below but I don't have full information about your table schema. Please try this-
select
#MID = MID,
#MName = Name,
#PID = PID,
#PName = PName,
#DID = DID
from #CompanyDataInfo
where id = #MCount
insert into #temp
select
f.Name,
f.PID,
f.PName,
v.*
from #CompanyDataInfo f
left join Employee v on v.Id=f.ID and v.DID=f.DID
where f.Id = #MID and
f.DId = #DId and
f.PId = #PId and
f.CId = #CId and
f.DATE_TIME between DATEADD(minute,-555,GETDATE()) and GETDATE() and
v.Id is null
order by f.DATE_TIME desc
Add ...and v.Id is null to your where clause.

How can this SQL subquery be expressed using Squeel/ActiveRecord?

I'm having a bit of brain fade today and can't figure out how I should express this SQL query correctly using ActiveRecord/Squeel/ARel:
SELECT `d1`.* FROM `domain_names` d1
WHERE `d1`.`created_at` = (
SELECT MAX(`d2`.`created_at`)
FROM `domain_names` d2
WHERE `d2`.`owner_type` = `d1`.`owner_type`
AND `d2`.`owner_id` = `d1`.`owner_id`
AND `d2`.`key` = `d1`.`key`
)
Any ideas?
Background: The DomainName model has a polymorphic owner as well as a "key" field that allows owners to have many different types of domain name. The query above fetches the latest domain name for each unique [owner_type, owner_id, key] tuple.
Edit:
Here's the same query using JOIN:
SELECT `d1`.* FROM `domain_names` d1
JOIN (
SELECT `owner_type`, `owner_id`, `key`, MAX(`created_at`) max_created_at
FROM `domain_names`
GROUP BY `owner_type`, `owner_id`, `key`
) d2
ON `d2`.`owner_type` = `d1`.`owner_type`
AND `d2`.`owner_id` = `d1`.`owner_id`
AND `d2`.`key` = `d1`.`key`
WHERE `d1`.`created_at` = `d2`.`max_created_at`

Strange execution time for summary query

I am giving here part of the query I am executing:
SELECT SUM(ParentTable.Field1),
(SELECT SUM(ChildrenTable.Field1)
FROM ChildrenRable INNER JOIN
GrandChildrenTable ON ChildrenTable.Id = GrandChildrenTable.ChildrenTableId INNER JOIN
AnotherTable ON GrandChildrenTable.AnotherTableId = AnotherTable.Id
WHERE ChildrenTable.ParentBaleId = ParentTable.Id
AND AnotherTable.Type=1),
----
FROM ParentTable
WHERE some_conditions
Relationships:
ParentTable -> ChildrenTable = 1-to-many
ChildrenTable -> GrandChildrenTable = 1-to-many
GrandChildrenTable -> AnotherTable = 1-to-1
I am executing this query three times, while changing only the Type condition, and here are the results:
Number of records that are returned:
Condition Total execution time (ms)
Type = 1 : 973
Type = 2 : 78810
Type = 3 : 648318
If I execute just the inner join query, here is the count of joined records:
SELECT p.Type, COUNT(*)
FROM CycleActivities ca INNER JOIN
CycleActivityProducts cap ON ca.Id = CAP.CycleActivityId INNER JOIN
Products p ON cap.ProductId = p.Id
GROUP BY p.Type
Type
---- -----------
1 55152
2 13401
4 102730
So, why would the query with Type = 1 condition execute much faster than the query with Type = 2, although it is querying 4x larger resultset (Type is tinyint)?
The way your query is written instructs SQL Server to execute the sub-query with JOIN for every row of the output.
This way it should be faster, if I understand what you want correctly (UPDATED):
with cte_parent as (
select
Id,
SUM (ParentTable.Field1) as Parent_Sum
from ParentTable
group by Id
),
cte_child as (
SELECT
Id,
SUM (ChildrenTable.Field1) as as Child_Sum
FROM ChildrenRable
INNER JOIN
GrandChildrenTable ON ChildrenTable.Id = GrandChildrenTable.ChildrenTableId
INNER JOIN
AnotherTable ON GrandChildrenTable.AnotherTableId = AnotherTable.Id
WHERE
AnotherTable.Type=1
AND
some_conditions
GROUP BY Id
)
select cte_parent.id, Parent_Sum, Child_Sum
from parent_cte
join child_cte on parent_cte.id = child_cte.id

JPQL join tables doubles column names

I have multiple tables in a join and every table has a column ID. So in the resultig join there are a lot of ID columns. How I can access a specific ID column with the criteria API?
ParameterExpression<A> idParam = criteriaBuilder.parameter(A.class, PARAM_NAME);
Subquery<B> sq = query.subquery(B.class);
Root<B> root = sq.from(B.class);
Join<C, D> joinTogether = root.join("memberX").join("memberY");
sq.select(root);
sq.where(criteriaBuilder.and(criteriaBuilder.equal(joinTogether.get("id"), idParam), criteriaBuilder.equal(parentQuery.get("id"), root.get("id"))));
The problem is, that in the resulting SQL contains
SELECT 1 FROM E t6, B t5, C t4, D t3 WHERE ((( = paramName) AND (t0.ID = t5.ID)) AND (((t6.memberZ = t5.ID) AND (t4.ID = t6.memberX)) AND (t3.ID = t4.memberY))))
The table E (t6) is an additional join table between table B and C, t0 is the reference to the parent query. Instead t3.id = :paramName EclipseLink creates nothing just before the first equal-sign (paramName is the content of the constant PARAM_NAME). My idea is, that the "id" column could reference all tables and EclipseLink can not decide, which table I mean.
How I can change that?
Thank you
André

Resources