Rails Activerecord Relation: using subquery as a table for a SQL select statement - sql

Can somebody help me figure out how to write the following SQL using Rails (I'm using Rails 4) Activerecord methods? I know you can do this with find_by_sql but I'd like to preserve the active record relation. Here's the sql for a postGreSQL db that I'm trying to create:
SELECT * FROM
(SELECT DISTINCT ON(table_a.id) table_a.name as alias_a, table_b.id, table_b.time
FROM table_1
LEFT OUTER JOIN table_b ON table_a.id = table_b.id
ORDER BY table_a.id, table_b.time asc) AS subquery
ORDER BY alias_a asc
For my subquery, I have the following (which generates the sql of the subquery above):
#subquery = table_a.select("DISTINCT ON(table_a.id) table_a.name as alias_a, table_b.time")
#subquery = #subquery.joins("LEFT OUTER JOIN table_b ON table_a.id = table_b.id")
#subquery = #subquery.order("table_a.id, table_b.time asc")
But, I can't figure out how to write a select statement that uses #subquery as the table for the outer select statement.

Use the from() method from the Active Record interface.
For example:
#subquery = table_a.select("DISTINCT ON(table_a.id) table_a.name as alias_a, table_b.time")
#subquery = #subquery.joins("LEFT OUTER JOIN table_b ON table_a.id = table_b.id")
#subquery = #subquery.order("table_a.id, table_b.time asc")
Then use it like this in the outer query:
#query = OtherModel.from("(#{#subquery.to_sql}) table_name, other_model_table, etc ...").where(:field => table_name.alias_a) ...etc.

This one is more elegant:
#subquery = Model.balalalala
#query = OtherModel.from(#subquery, :sub_query).where(sub_query: {column_b: balalala}).order('sub_query.column_a')

Related

Oracle compare results from query against a table

I need to compare results from a query against a table. I have the following query:
select
i.person_id,
a.APPELLANT_FIRST_NAME,
a.APPELLANT_MIDDLE_NAME,
a.APPELLANT_LAST_NAME,
a.databaseidnumber,
a.CTAPPEALSNUMBER,
a.NOTICEOFAPPEALFILEDDATE,
a.RECORDDUEDATE,
a.PETITIONONAPPEALDUEDATE,
a.PETITIONONAPPEALFILEDDATE,
a.RESPONSETOPETITIONDUEDATE,
a.RESPONSETOPETITIONFILEDDATE,
a.CERTFILEDDATE,
a.MANDATEISSUEDDATE
from CWLEGAL.individuals i inner join CWLEGAL.tblappealsdatarevisionone a
on a.d_n_number1 = i.casenm and a.appellant_first_name = i.first_name and a.appellant_last_name = i.last_name
order by databaseidnumber;
Now I need to see what databaseidnumber's from Table A don't appear in the results from the query above.
You can use left join and check for null:
select a.*
from CWLEGAL.tblappealsdatarevisionone a left join
CWLEGAL.individuals i
on a.d_n_number1 = i.casenm and
a.appellant_first_name = i.first_name and
a.appellant_last_name = i.last_name
where i.casenm is null

SQL Intersect not supported in Phoenix , alternative for intersect in phoenix?

I have the following SQL expression:
SELECT SS_ITEM_SK AS POP_ITEM_SK
FROM (SELECT SS_ITEM_SK
FROM (SELECT SS_ITEM_SK,(ITEM_SOLD-ITEM_RETURNED) AS TOT_SOLD_QTY FROM (SELECT SS_ITEM_SK,COUNT(SS_ITEM_SK) AS ITEM_SOLD,COUNT(SR_ITEM_SK) AS ITEM_RETURNED FROM STORE_SALES1 right outer join STORE_RETURNS1 on SS_TICKET_NUMBER = SR_TICKET_NUMBER AND SS_ITEM_SK = SR_ITEM_SK GROUP BY SS_ITEM_SK)))
INTERSECT
SELECT CS_ITEM_SK AS POP_ITEM_SK FROM (SELECT CS_ITEM_SK
FROM (SELECT CS_ITEM_SK,(ITEM_SOLD-ITEM_RETURNED) AS TOT_SOLD_QTY FROM (SELECT CS_ITEM_SK,COUNT(CS_ITEM_SK) AS ITEM_SOLD,COUNT(CR_ITEM_SK) AS ITEM_RETURNED FROM CATALOG_SALES1 right outer join CATALOG_RETURNS1 on CS_ORDER_NUMBER = CR_ORDER_NUMBER and CS_ITEM_SK = CR_ITEM_SK GROUP BY CS_ITEM_SK)))
INTERSECT
SELECT WS_ITEM_SK AS POP_ITEM_SK FROM (SELECT WS_ITEM_SK
FROM (SELECT WS_ITEM_SK,(ITEM_SOLD-ITEM_RETURNED) AS TOT_SOLD_QTY FROM (SELECT WS_ITEM_SK,COUNT(WS_ITEM_SK) AS ITEM_SOLD,COUNT(WR_ITEM_SK) AS ITEM_RETURNED FROM WEB_SALES1 right outer join WEB_RETURNS1 on WS_ORDER_NUMBER = WR_ORDER_NUMBER AND WS_ITEM_SK = WR_ITEM_SK GROUP BY WS_ITEM_SK)))
Apache phoenix is not supporting the keyword INTERSECT. Can somebody please help me to correct above query without using INTERSECT?
I think there are multiple ways you can do this:
Join Method
select * from ((query1 inner join query2 on column_names) inner join query3 on column_names)
Exists Method
(query1 where exists (query2 where exists (query3)) )
In Method
(query1 where column_name in (query2 where column_name in (query3)) )
References: https://blog.jooq.org/2015/10/06/you-probably-dont-use-sql-intersect-or-except-often-enough/
and http://phoenix.apache.org/subqueries.html
Although I would use the exists/in over the join since if these queries return huge data then you might have to optimize your queries using this:
https://phoenix.apache.org/joins.html

How to use subquery in the join function of Yii framework 2 ActiveRecord?

Below is my pure SQL query.
SELECT a.*, b.*
FROM a
INNER JOIN b
ON a.id = b.a_id
INNER JOIN (
SELECT a_id, MAX(add_time) AS max_add_time
FROM b
GROUP BY a_id
) m
ON b.a_id = m.a_id AND b.add_time = m.max_add_time
ORDER BY b.add_time DESC
I have the subquery in the second INNER JOIN. Below my active query.
$subQuery = B::find()->select(['a_id', 'MAX(add_time) AS max_add_time'])->groupBy('a_id');
$query = A::find()->innerJoin('b', 'a.id = b.a_id')
->innerJoin('(' .
$subQuery->prepare(Yii::$app->db->queryBuilder)
->createCommand()
->rawSql
. ') m', 'b.a_id = m.a_id AND a.add_time = m.max_add_time ')
->orderBy('b.add_time DESC');
It works fine, but I do not like the way I use the subquery in the second INNER JOIN. What I want to approach with this query is to select the left table inner join with right table, group by a_id and order by the add_time (DESC) of the right table. How should I better use the subquery in the second INNER JOIN?
The snippet below is untested but it should be something like that. If you read the docs (at http://www.yiiframework.com/doc-2.0/yii-db-query.html#innerJoin()-detail) you can see an array with a subquery is also valid input, with the key being the alias.
$subQuery = B::find()
->select(['a_id', 'MAX(add_time) AS max_add_time'])
->groupBy('a_id');
$query = A::find()
->innerJoin('b', 'a.id = b.a_id')
->innerJoin(['m' => $subQuery], 'b.a_id = m.a_id AND a.add_time = m.max_add_time')
->orderBy('b.add_time DESC');
Having created the join, if you need to use any of the columns returned by the subQuery, you need to add properties to the Yii2 model class, e.g.
$subQuery = FinancialTransaction::find()
->select( new \yii\db\Expression( 'SUM(amount) as owing') )
->addSelect('booking_id')
->groupBy('booking_id');
$query = $query
->addSelect(['b.*', 'owing'])
->leftJoin(['ft' => $subQuery], 'b.booking_display_id = ft.booking_id');
To access "owing" the model has to have the property (PHPdoc optional):
/**
* #var float
*/
public $owing=0;

How can I convert a SQL query with a derived table to HQL?

SELECT *
FROM visitdetails vd
LEFT JOIN
(SELECT MAX(id) AS id, VisitID
FROM claimfilelist GROUP BY VisitID) cf ON cf.visitid = vd.Id
LEFT JOIN claimfilelist cf1 ON cf1.id = cf.id
I have this SQL query. How can I convert it to HQL?
The HQL-documentation says that subqueries are only allowed in SELECT and WHERE. So, my first step is to move the subquery to the WHERE-clause:
SELECT *
FROM visitdetails vd
LEFT JOIN claimfilelist cf ON cf.visitid = vd.id
WHERE cf.id IS NULL OR cf.id = (
SELECT max(cfInner.id)
FROM claimfilelist cfInner
WHERE cfInner.visitId = vd.id
)
Depending on your Hibernate - version you might need to change the joins. I am not sure if the query works, but you could give the approach a try.

Invalid SQL Query

I have the next query that in my opinion is a valid one, but I keep getting error telling me that there is a proble on "WHERE em.p4 = ue.p3" - Unknown column 'ue.p3' in 'where clause'.
This is the query:
SELECT DISTINCT ue.p3
FROM
table1 AS ue INNER JOIN table2 AS e
ON ue.p3 = e.p3
WHERE
EXISTS(
SELECT 1 FROM (
SELECT (COUNT(*) >= 1) AS MinMutual
FROM table4 AS smm
WHERE
smm.p1 IN (
SELECT sem.p3 FROM table3 AS sem
INNER JOIN table2 AS em ON sem.p3 = em.p3
WHERE em.p4 = ue.p3 AND
sem.type = 'friends' AND em.p2 = 'normal' ) AND
smm.p5 IN (
15000,15151
)
) AS Mutual WHERE
Mutual.MinMutual = TRUE) LIMIT 11
If I execute the sub-query which is inside the EXISTS function, everything is O.K.
PLEASE HELP!
The reason for the error is that you can only reference one subquery layer down when correlating. Look at where the ue alias is defined, and count the number of FROM clauses until to you reach the next reference.
I re-wrote your query as:
SELECT DISTINCT ue.p3
FROM table1 AS ue
JOIN table2 AS e ON ue.p3 = e.p3
WHERE EXISTS(SELECT 1 AS MinMutual
FROM table4 AS smm
JOIN TABLE3 sem ON sem.p3 = smm.p1
AND sem.type = 'friends'
JOIN TABLE2 em ON em.p3 = sem.p3
AND em.p3 = ue.p3
AND em.p2 = 'normal'
WHERE smm.p5 IN (15000,15151)
GROUP BY ? --needs a group by clause, in order to use HAVING
HAVING COUNT(*) >= 1)
LIMIT 11
EXISTS returns true if satisfied -- it doesn't evaluate based on the subquery returning "true". There's no need for the additional subquery you have (which was causing problems anyway).
AFAIK, this kind of correlated query is not doable in mysql as of now. Join to a derived table as opposed to using the exists.