Rails 3.2 - How to turn this complex query to be in parameterized format? - sql

I am currently helping out a Rails 3.2 project.
Got this complex query that I would like to be in parameterized format.
project.supporters.connection.select_all( "SELECT t2.* FROM
(SELECT MAX(id) AS max_supporter_id FROM supporters WHERE
supporters.project_id = ? GROUP BY supporters.supporter_id) AS
t1 INNER JOIN supporters AS t2 ON t1.max_supporter_id =
t2.id", 1).
Above query is what I would like to be like but I know it doesn't work because select_all doesn't do parameterized query.
So far this is what I got:
project.supporters.group(:supporter_id).maximum(:id) which will
generate this sql: SELECT MAX("supporters"."id") AS maximum_id,
supporter_id AS supporter_id FROM "supporters" WHERE
"supporters"."project_id" = 1 GROUP BY supporter_id
But I haven't made significant progress to do the inner join and finally have the outer SELECT.
Can anyone help?

project_id = 1
supporters = Arel::Table.new(:supporters)
max_id = supporters.project(supporters[:id].maximum.as('max_supporters_id')).group(supporters[:supporter_id])
query = supporters.project(max_id)
.join(supporters[:project_id])
.on(supporters[:max_supporter_id].eq(supporters[:id]))
.where(supporters[:project_id].eq(project_id))
query.to_sql
# => "SELECT (SELECT MAX(\"supporters\".\"id\") AS max_supporters_id FROM \"supporters\" GROUP BY \"supporters\".\"supporter_id\") FROM \"supporters\" INNER JOIN \"supporters\".\"project_id\" ON \"supporters\".\"max_supporter_id\" = \"supporters\".\"id\" WHERE \"supporters\".\"project_id\" = 1"
query.to_a # executes the query and returns records
For more informations about building the complex queries in rails, you could read there https://github.com/rails/arel
I wish it helps.

Related

How to Join two Queries in Sequelize

I tried to join two queries and based on it find the result. I am able to write the code in SQL. My SQL Code is
SELECT a.awbid,
m.mpscount
FROM ( select a.awbid
FROM awbmaster a
where a.batchid ='B/117/15022022'
and a.hubid ='117'
) as a
left join ( select count('mpsid') as "mpscount" ,
awbid from
mpsmaster m
where m.batchid = 'B/117/15022022'
group by "awbid"
) as m on a.awbid = m.awbid
But, I am not yet found any solution regarding the sequelize. How can I write the above SQL code in sequelize?
First, we can simplify this SQL query simply using a subquery to find out mpscount:
SELECT a.awbid,
(SELECT count(*)
FROM mpsmaster m
WHERE m.batchid = 'B/117/15022022'
AND m.awbid=a.awbid ) AS mpscount
FROM awbmaster a
WHERE a.batchid ='B/117/15022022'
AND a.hubid ='117'
Now if we already have both models MpsMaster and AwbMaster and a correct association between them then we can make a request something like this:
const records = AwbMaster.findAll(}
attributes: [
'awbid',
[Sequelize.literal('(SELECT count(*) FROM mpsmaster m WHERE m.batchid = \'B/117/15022022\' AND m.awbid=AwbMaster.awbid)'), 'mpscount']
]
})

Un-nesting a nested SQL query

I am new to building sql queries and could use some help. I built a query that works fine as a standalone query. The problem is I need to use it in a report using ExecuteScalar function and nested queries are not allowed, I tried to rebuild using joins but I seem to be lost.
Can anyone help me "un-nest" this query?
SELECT
StockType2Job.Loaded
FROM
StockType2Job
WHERE
StockType2Job.IdStockType =
(SELECT StockType.IdStockType
FROM StockType
WHERE StockType.Number = '1001716.00')
AND
StockType2Job.IdStockType2JobGroup =
(SELECT StockType2JobGroup.IdStockType2JobGroup
FROM StockType2JobGroup
WHERE StockType2JobGroup.IdJob =
(SELECT Job.IdJob
FROM Job
WHERE Job.Number = '18-0085.02'
AND StockType2JobGroup.Caption = 'Breakout Room 1'))
Any help appreciated. Thanks
this query should work(on Oracle DB):
SELECT
StockType2Job.Loaded
FROM
(((StockType2Job a JOIN StockType b ON a.IdStockType=b.IdStockType)
JOIN StockType2JobGroup c ON a.IdStockType2JobGroup=c.IdStockType2JobGroup)
JOIN Job d ON c.IdJob=d.IdJob)
WHERE
b.Number = '1001716.00' AND
d.Number = '18-0085.02' AND
c.Caption = 'Breakout Room 1'

DISTINCT SQL query with inner joins that omits a column from considerations,

I have a DB2 query as follows:
SELECT DISTINCT RETAILMASTERFILE.DOIDCD AS "RETAILMASTERFILE_DOIDCD",
RETAILMASTERFILE.COCOMO AS "RETAILMASTERFILE_COCOMO",
#XENOS.CUSTREF AS "XENOS_CUSTREF",
#XENOS.ADDUDT AS "XENOS_ADDUDT",
#XENOS.ADUPDD AS "XENOS_ADUPDD",
#XENOS.ADUPDT AS "XENOS_ADUPDT",
#XENOS.ADSTAT AS "XENOS_ADSTAT"
FROM RETAILMASTERFILE INNER JOIN
#XENOS ON RETAILMASTERFILE.DOCOMP = #XENOS.ADCOMP
AND RETAILMASTERFILE.COCOMO = #XENOS.ADDELN
WHERE (RETAILMASTERFILE.DOIDCD = 'CUST008')
AND (RETAILMASTERFILE.COCOMO = '345126032')
AND (RETAILMASTERFILE.DOCOMP = 'LONDON')
The problem is #XENOS.ADUPDT may not be unique which gives me an unwanted duplicate record.
Is there any way I can exclude this from consideration ? Everything I've tried so far within my limited knowledge and crude understanding of group by has so far broken my query.
Use GROUP BY instead:
SELECT RETAILMASTERFILE.DOIDCD AS "RETAILMASTERFILE_DOIDCD",
RETAILMASTERFILE.COCOMO AS "RETAILMASTERFILE_COCOMO",
#XENOS.CUSTREF AS "XENOS_CUSTREF",
#XENOS.ADDUDT AS "XENOS_ADDUDT",
#XENOS.ADUPDD AS "XENOS_ADUPDD",
MAX(#XENOS.ADUPDT) AS "XENOS_ADUPDT",
#XENOS.ADSTAT AS "XENOS_ADSTAT"
FROM RETAILMASTERFILE INNER JOIN
#XENOS
ON RETAILMASTERFILE.DOCOMP = #XENOS.ADCOMP AND
RETAILMASTERFILE.COCOMO = #XENOS.ADDELN
WHERE (RETAILMASTERFILE.DOIDCD = 'CUST008') AND (RETAILMASTERFILE.COCOMO = '345126032') AND
(RETAILMASTERFILE.DOCOMP = 'LONDON')
GROUP BY RETAILMASTERFILE.DOIDCD,
RETAILMASTERFILE.COCOMO,
#XENOS.CUSTREF,
#XENOS.ADDUDT,
#XENOS.ADUPDD,
#XENOS.ADSTAT;

SQL query for filtering data

I`m working on some sql queries to get some data out of a table; I have made 2 queries for the
same data but both give another result. The 2 queries are:
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN (
( patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id) AND
(patient.Sample = Samples.Sample)
) ON
(tissue.Sample_Name = data_overview.Sample_Name) AND
(tissue.Sample_Name = patient.Sample_Name)
WHERE data_overview.Sentrix_ID= 1416198
OR data_overview.Pool_ID='GS0005701-OPA'
OR data_overview.Pool_ID='GS0005702-OPA'
OR data_overview.Pool_ID='GS0005703-OPA'
OR data_overview.Pool_ID='GS0005704-OPA'
OR data_overview.Sentrix_ID= 1280307
ORDER BY Samples.Sample;")
And the other is
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN
(
(patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id)
AND (patient.Sample = Samples.Sample)) ON
(tissue.Sample_Name = data_overview.Sample_Name)
AND (tissue.Sample_Name = patient.Sample_Name)
WHERE ((
(data_overview.Sentrix_ID)=1280307)
AND (
(data_overview.Pool_ID)="GS0005701-OPA"
OR (data_overview.Pool_ID)="GS0005702-OPA"
OR (data_overview.Pool_ID)="GS0005703-OPA"
OR (data_overview.Pool_ID)="GS0005704-OPA"))
OR (((data_overview.Sentrix_ID)=1416198))
ORDER BY data_overview.Sample;
The one in the top is working quite well but it still won't filter the sentrix_ID.
The second 1 is created with Access but when I try to run this Query in R it gave
a unexpected symbol error. So if anyone knows how to create a query that filter POOL_ID and Sentrix_id with the given parameters thanks in advance
Is it a case of making the where clause something like this:
WHERE Sentrix_ID = 1280307 AND (Pool_ID = 'VAL1' OR Pool_ID = 'VAL2' OR Pool_ID = 'VAL3')
i.e. making sure you have brackets around the "OR" components?
Maybe you meant:
...
WHERE data_overview.Sentrix_ID IN (1280307,1416198 )
AND data_overview.Pool_ID IN ("GS0005701-OPA", "GS0005702-OPA", "GS0005703-OPA" ,"GS0005704-OPA")
;

Problem with adding custom sql to finder condition

I am trying to add the following custom sql to a finder condition and there is something not quite right.. I am not an sql expert but had this worked out with a friend who is..(yet they are not familiar with rubyonrails or activerecord or finder)
status_search = "select p.*
from policies p
where exists
(select 0 from status_changes sc
where sc.policy_id = p.id
and sc.status_id = '"+search[:status_id].to_s+"'
and sc.created_at between "+status_date_start.to_s+" and "+status_date_end.to_s+")
or exists
(select 0 from status_changes sc
where sc.created_at =
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < "+status_date_start.to_s+")
and sc.status_id = '"+search[:status_id].to_s+"'
and sc.policy_id = p.id)" unless search[:status_id].blank?
My find statement:
Policy.find(:all,:include=>[{:client=>[:agent,:source_id,:source_code]},{:status_changes=>:status}],
:conditions=>[status_search])
and I am getting this error message in my log:
ActiveRecord::StatementInvalid (Mysql::Error: Operand should contain 1 column(s): SELECT DISTINCT `policies`.id FROM `policies` LEFT OUTER JOIN `clients` ON `clients`.id = `policies`.client_id WHERE ((((policies.created_at BETWEEN '2009-01-01' AND '2009-03-10' OR policies.created_at = '2009-01-01' OR policies.created_at = '2009-03-10')))) AND (select p.*
from policies p
where exists
(select 0 from status_changes sc
where sc.policy_id = p.id
and sc.status_id = '2'
and sc.created_at between 2009-03-10 and 2009-03-10)
or exists
(select 0 from status_changes sc
where sc.created_at =
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < 2009-03-10)
and sc.status_id = '2'
and sc.policy_id = p.id)) ORDER BY clients.created_at DESC LIMIT 0, 25):
what is the major malfunction here - why is it complaining about the columns?
The conditions modifier is expecting a condition (e.g. a boolean expression that could go in a where clause) and you are passing it an entire query (a select statement).
It looks as if you are trying to do too much in one go here, and should break it down into smaller steps. A few suggestions:
use the query with find_by_sql and don't mess with the conditions.
use the rails finders and filter the records in the rails code
Also, note that constructing a query this way isn't secure if the values like status_date_start can come from users. Look up "sql injection attacks" to see what the problem is, and read the rails documentation & examples for find_by_sql to see how to avoid them.
Ok, I've managed to retool this so it is more friendly to a conditions modifier and I think it is doing the sql query correctly.. however, it is returning policies that when I try to list the current status (the policy.status_change.last.status) it is set to the same status used in the query - which is not correct
here is my updated condition string..
status_search = "status_changes.created_at between ? and ? and status_changes.status_id = ?) or
(status_changes.created_at = (SELECT MAX(sc2.created_at) FROM status_changes sc2
WHERE sc2.policy_id = policies.id and sc2.created_at < ?) and status_changes.status_id = ?"
is there something obvious to this that is not returning all of the remaining associated status changes once it finds the one in the query?
here is the updated find..
Policy.find(:all,:include=>[{:client=>[:agent,:source_id,:source_code]},:status_changes],
:conditions=>[status_search,status_date_start,status_date_end,search[:status_id].to_s,status_date_start,search[:status_id].to_s])