p = Patient.find(30)
p.patient_problems
The above code generates the following query
SELECT `patient_problem`.* FROM `patient_problem` WHERE `patient_problem`.`patient_id` = 30 AND (`patient_problem`.`record_status_id` = 1)
But is there any way to assign/use alias table_name like
p.patient_problems(:alias=>'p1') # just for Ex.. This code will not work
p.patient_problems(:alias=>'p2') # just for Ex.. This code will not work
So it will generate the following queries
SELECT `p1`.* FROM `patient_problem` AS `p1` WHERE `p1`.`patient_id` = 30 AND (`p1`.`record_status_id` = 1)
SELECT `p2`.* FROM `patient_problem` AS `p2` WHERE `p2`.`patient_id` = 30 AND (`p2`.`record_status_id` = 1)
Additional Info
My problem is when I try to use joins
p.patient_problems(:all,:joins=>joins)
I get this error
ActionView::Template::Error (Mysql2::Error: Not unique table/alias: 'patient_problem': SELECT `patient_problem`.* FROM `patient_problem` LEFT OUTER JOIN party on party.id = patient_problem.patient_id
LEFT OUTER JOIN party_identifier on party.id = party_identifier.party_id
LEFT OUTER JOIN blood_type on blood_type.id = party.blood_type_id
LEFT OUTER JOIN education_level on education_level.id = party.education_level_id
LEFT OUTER JOIN religion on religion.id = party.religion_id
LEFT OUTER JOIN living_arrangement on living_arrangement.id = party.living_arrangement_id
LEFT OUTER JOIN patient_problem patient_problem on patient_problem.patient_id = party.id and patient_problem.record_status_id = 1
left join (select user_type,username,user_id,auditable_id from (select MAX(id) id from audits where audits.auditable_type = 'PatientProblem' and user_type is not null group by auditable_id ) t inner join audits v on v.id=t.id ) entered_by1 on entered_by1.auditable_id = patient_problem.id
left outer join user user1 on entered_by1.user_id = user1.id
left outer join party as party_user1 on party_user1.id = user1.person_id
LEFT OUTER JOIN patient_patient_search patient_patient_search1 on patient_patient_search1.patient_id = party.id
left join search search1 on patient_patient_search1.patient_search_id = search1.id
and patient_patient_search1.patient_search_id = '75' WHERE `patient_problem`.`patient_id` = 45 AND (`patient_problem`.`record_status_id` = 1) AND ( (patient_problem.occurrence_date > '2013-01-01 00:00:00' and patient_problem.occurrence_date < '2013-06-30 23:59:59' and patient_problem.patient_problem_status_id in (5) and patient_problem.code is not null and patient_problem.code in ('10725009') ) and ( patient_patient_search1.patient_search_id in (75.0) ) ))
Ofcourse I could do some string manipulation on the generated joins query and set alias to patient_problem. But I thought setting alias for associations would be more cleaner since the joins query generated are unpredictable(in my scenario)
I am not sure what the variable joins is or how it was constructed. To alias tables in a join build your query like
Rails 3
PatientProblem.joins("as p1 OUTER JOIN patient_problem as p2 on ...")
or
PatientProblem.find(:all, :joins => "as p1 OUTER JOIN patient_problem as p2 ON ...")
you can make singleton methods for that and write the query one time and use may time like
def self.p1
#your active record query here.
end
and call like
PatientProblem.p1
Update
You can simply change the table name in your code:
Patient.table_name="p2"
I'm not sure if this would break anything else though ... so good luck!
Orignal Answer
One solution may be to define a separate model for each type of patient_problem and then do something like this:
class PatientProblem2 < ActiveRecord::Base
self.set_table_name "p2"
...
end
Another solution may be to use the ActiveRecord query interface which will allows for significant query flexibility:
http://guides.rubyonrails.org/active_record_querying.html
Perhaps you can be more specific on the nature problem you are trying to solve.
Related
How can I access data from an outer table in a SELECT, and use it in an WHERE inside a JOIN estructure?
Below is the current query:
SELECT
cvl.id caracteristica_valor_id,
cvl.nome caracteristica_valor_nome,
cvl.valor caracteristica_valor_valor,
ctp.id caracteristica_tipo_id,
ctp.nome caracteristica_tipo_nome,
ctp.codigo caracteristica_tipo_codigo,
ctp.tipo caracteristica_tipo_tipo,
COUNT(DISTINCT var.id_perfil_produto) quantidade_itens
FROM
caracteristica_variacao cvr
INNER JOIN caracteristica_valor cvl ON cvl.id = cvr.id_caracteristica_valor
INNER JOIN caracteristica_tipo ctp ON ctp.id = cvl.id_caracteristica_tipo
INNER JOIN variacao var ON var.id = cvr.id_variacao
INNER JOIN(
SELECT DISTINCT
ppr.id perfil_produto_id
FROM
perfil_produto ppr
INNER JOIN produto pro ON pro.id = ppr.id_produto
INNER JOIN(
SELECT ppr2.id AS id_perfil_sub,a
COUNT(var.id) AS qtd_variacoes,
SUM(var.quantidade_estoque) AS quantidade_estoque,
COALESCE(SUM(var.quantidade_estoque_reservada),0) AS quantidade_estoque_reservada,
MIN(var.disponibilidade) AS disponibilidade,
MIN(var.frete_gratis) AS frete_gratis,
MIN(var.preco_venda) AS preco_venda,
MAX(var.preco_listagem) AS preco_listagem
FROM
variacao var
LEFT JOIN perfil_produto ppr2 ON ppr2.id = var.id_perfil_produto
LEFT JOIN caracteristica_variacao cvr_1 ON cvr_1.id_variacao = var.id
LEFT JOIN caracteristica_valor cvl_1 ON cvl_1.id = cvr_1.id_caracteristica_valor
LEFT JOIN caracteristica_tipo ctp_1 ON ctp_1.id = cvl_1.id_caracteristica_tipo
WHERE
var.disponibilidade = 1
AND(
ctp_1.codigo = 'tamanho' AND cvl_1.valor IN('p')
)
GROUP BY
ppr2.id
) AS grp_var ON grp_var.id_perfil_sub = ppr.id
INNER JOIN produto_categoria prc ON pro.id = prc.produto_id
INNER JOIN categoria cat ON prc.categoria_id = cat.id
WHERE
pro.disponibilidade = 1 AND prc.categoria_id IN (164, 165, 166)
) AS produto ON produto.perfil_produto_id = var.id_perfil_produto
GROUP BY
cvl.id
ORDER BY
ctp.tipo ASC,
ctp.id
I need the field ctp.codigo from the outer table inside thist part:
WHERE
var.disponibilidade = 1
AND(
ctp_1.codigo = 'tamanho' AND cvl_1.valor IN('p')
)
for this section to be as follows:
WHERE
var.disponibilidade = 1
AND(
(ctp.codigo != 'tamanho' AND ctp_1.codigo = 'tamanho' AND cvl_1.valor IN('p'))
OR
(ctp.codigo = 'tamanho')
)
It's not possible to reference columns from the outer query from inside an inline view query.
In the MySQL venacular, the inline view query is called a "derived table". And that name makes sense, because of the way MySQL processes it. The execution plan first materializes the inline view query into a temporary(-ish) table. Once that is done, then the outer query can run, referencing the contents of the derived table.
MySQL doesn't have available the columns from the outer query at the time the inline view query runs.
It is possible to reference columns from the outer query inside a subquery that appears for example in the SELECT list, or in the WHERE clause. We call a subquery that references columns from outer query a "correlated subquery".
I want to create a view which combines the data with the maximal date from the tables shown in the picture. These should be grouped by the profileID.
Database ERM
The profileIDs are linked to profile.userID.
I tried different approches in my code. The fort one slects the data where date is max, but the join doesn't work. Every profileID will be joined with the same data.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `b91788dd8d05b5`#`%`
SQL SECURITY DEFINER
VIEW fitchallengersql1.profileview AS
Select p.userID,
(SELECT
`bf`.`bodyFat`
FROM
(`fitchallengersql1`.`bodyfatprofile` `bf`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bf`.`profileID` = `p`.`userID`)
AND (`bf`.`date` = (SELECT
MAX(`fitchallengersql1`.`bodyfatprofile`.`date`)
FROM
`fitchallengersql1`.`bodyfatprofile`)))) AS `bodyFat`,
(SELECT
`bw`.`bodyweight`
FROM
(`fitchallengersql1`.`bodyweightprofile` `bw`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bw`.`profileID` = `p`.`userID`)
AND (`bw`.`date` = (SELECT
MAX(`fitchallengersql1`.`bodyweightprofile`.`date`)
FROM
`fitchallengersql1`.`bodyweightprofile`)))) AS `bodyWeight`,
(SELECT
`bmi`.`bmi`
FROM
(`fitchallengersql1`.`bmiprofile` `bmi`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bmi`.`profileID` = `p`.`userID`)
AND (`bmi`.`date` = (SELECT
MAX(`fitchallengersql1`.`bmiprofile`.`date`)
FROM
`fitchallengersql1`.`bmiprofile`)))) AS `bmi`
From profile
In the second one the join works how it should, but I can't figure out a way to select just the data where date is max.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `b91788dd8d05b5`#`%`
SQL SECURITY DEFINER
VIEW `fitchallengersql1`.`profileview` AS
SELECT
`p`.`userID` AS `userID`,
`p`.`privacy` AS `privacy`,
`bs`.`size` AS `bodysize`,
`bw`.`bodyweight` AS `bodyweight`,
`bf`.`bodyFat` AS `bodyfat`,
`bmi`.`bmi` AS `bmi`
FROM
((((`fitchallengersql1`.`profile` `p`
JOIN `fitchallengersql1`.`bodysizeprofile` `bs`)
JOIN `fitchallengersql1`.`bodyweightprofile` `bw`)
JOIN `fitchallengersql1`.`bmiprofile` `bmi`)
JOIN `fitchallengersql1`.`bodyfatprofile` `bf`)
WHERE
((`p`.`userID` = `bs`.`profileID`)
AND (`p`.`userID` = `bw`.`profileID`)
AND (`p`.`userID` = `bmi`.`profileID`)
AND (`p`.`userID` = `bf`.`profileID`))
Hope someone could help me.
Thank you!
fleewe
Hope following query gives what you need. Please follow the pattern and join the rest of the tables. Please note that when the table grows these will definitely have performance issues as this require huge processing.
-- Select the columns that you need
select p.*, lbp.*
from profile p
inner join (
-- get the latest bmiprofile per user profile
select bp1.*
from bmiprofile bp1
inner join (select profileID, max(date) as date from bmiprofile group by profileID) as bp2 on bp1.prfileId = bp2.profileId and bp1.date = bp2.date
) as lbp on lbp.ProfileId = p.userId
-- Join the other tables in similar way
this is only a comment, but I needed formating capability:
Don't place the joining predicates into the where clause if using ANSI join syntax, instead use ON followed by the relevant predicates. e.g.
FROM `fitchallengersql1`.`profile` `p`
JOIN `fitchallengersql1`.`bodysizeprofile` `bs` ON `p`.`userID` = `bs`.`profileID`
JOIN `fitchallengersql1`.`bodyweightprofile` `bw` ON `p`.`userID` = `bw`.`profileID`
JOIN `fitchallengersql1`.`bmiprofile` `bmi` ON `p`.`userID` = `bmi`.`profileID`
JOIN `fitchallengersql1`.`bodyfatprofile` `bf` ON `p`.`userID` = `bf`.`profileID`
Is there a way I can generate this query with cakePHP :
SELECT pl.zban_player_id 'Player', pl.display_info 'GUID', pl.source_group 'Source',
IF(pv.variable_value is not null, 1,0) as SyncProcessed
FROM banner_key_current bkc
INNER JOIN banner_key_current_ext bkce ON bkc.banner_key_id = bkce.banner_key_id
INNER JOIN operations op ON op.operation_id = bkc.operation_id
INNER JOIN players pl ON pl.zban_player_id = bkce.identifier
INNER JOIN playermap_now pmn ON pmn.zban_player_id = pl.zban_player_id
LEFT JOIN player_variables pv ON (pv.zban_player_id = pl.zban_player_id AND pv.variable_name = 'player_sync_processed')
WHERE bkc.date BETWEEN '2014-05-01' AND '2014-11-13'
AND op.category = 117
AND pmn.user_id IN (1)
Group By bkce.identifier
What I want to return is the alias field SyncProcessed based on the condition
I'v tried using joins but couldn't get this result
You can use custom query by using this :
$this->YourModel->query('your query here')
SELECT TIME(ADDTIME(departure, SEC_TO_TIME(SUM(jptl2.run_time)))) AS departure,
service.line_name AS line,
bus.registration
FROM vehicle_journey
LEFT JOIN bus ON bus.journey = vehicle_journey.code AND
ADDTIME(TIME(NOW()), SEC_TO_TIME(3600)) > vehicle_journey.departure AND
ADDTIME(TIME(NOW()), SEC_TO_TIME(3600)) < ADDTIME(vehicle_journey.departure, SEC_TO_TIME(SUM(jptl.run_time)))
INNER JOIN service ON service.reference = vehicle_journey.service_reference
INNER JOIN vehicle_journey_days ON vehicle_journey_days.journey_reference = vehicle_journey.reference
INNER JOIN journey_pattern ON journey_pattern.reference = vehicle_journey.journey_pattern_reference
INNER JOIN journey_pattern_timing_link jptl ON jptl.section = journey_pattern.journey_pattern_section
INNER JOIN journey_pattern_timing_link jptl2 ON jptl2.section = journey_pattern.journey_pattern_section AND jptl2.ID < jptl.id
WHERE jptl.stop = '1900HA030334' AND vehicle_journey_days.day = 'MondayToFriday'
GROUP BY vehicle_journey.id
The above SQL query returns: #1111 - Invalid use of group function
I Know that this issue is caused by the third ON in the LEFT JOIN bus clause. How can I rewrite the query so it saves the same purpose and joins based on the same requirements but without the group function error?
Can I just write the SEC_TO_TIME(SUM(jptl.run_time)) as a sub query?
EG: (SELECT SEC_TO_TIME(SUM(jptl.run_time)))
You cannot use a group function in a [LEFT] JOIN condition, because at this stage, the group are still in the process of being constructed (and the contents of these groups depend on the join conditions, so this would create a sort of circular reference).
First construct your groups, then join the table that depends on these groups:
SELECT groups.*, bus.registration
FROM (
SELECT
TIME(...) AS departure,
service.line_name AS line,
ADDTIME(vehicle_journey.departure, SEC_TO_TIME(SUM(jptl.run_time)))
AS upper_limit,
vehicle_journey.code
AS vj_code,
vehicle_journey.departure
AS vj_departure
FROM vehicle_journey
-- skip "bus" for now
JOIN service ...
-- add all remaining JOIN's here
WHERE ...
GROUP BY vehicle_journey.id
) AS groups
LEFT JOIN bus
ON bus.journey = vj_code
AND ADDTIME(TIME(NOW()), SEC_TO_TIME(3600)) > vj_departure
AND ADDTIME(TIME(NOW()), SEC_TO_TIME(3600)) < upper_limit;
You could also simply move the offending condition down to a HAVING clause, but this would not return records with no match in bus (effectively turning the LEFT JOIN into a INNER JOIN):
SELECT
...
FROM vehicle_journey
LEFT JOIN bus ON bus.journey = vehicle_journey.code AND
ADDTIME(TIME(NOW()), SEC_TO_TIME(3600)) > vehicle_journey.departure
-- no reference to "SUM(jptl.run_time)" here
JOIN service ...
WHERE ...
GROUP BY vehicle_journey.id
-- and here is the reference to "SUM(jptl.run_time)"
HAVING ADDTIME(TIME(NOW()), SEC_TO_TIME(3600))
< ADDTIME(vehicle_journey.departure, SEC_TO_TIME(SUM(jptl.run_time)))
I currently have this working using a Sub-query, but as the DB grows this will become HUGELY inefficient. I'm wondering if there is a more efficient way to do what I need to do without sub-queries?
I need to have my final output look like so:
Question, Answer, Responses, Charts included in Response Count
Did this work?, N/A, 26, 30
Did this work?, Yes, 4, 30
This is my current query:
SELECT
bq_text,
ba_a,
bq_id,
COUNT(ba_a) AS ba_aC,
(SELECT COUNT(*) FROM board_done_sheet WHERE sd_b_id = bs.bs_id AND sd_sub = 1) AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
LEFT JOIN boardsubs bs
ON (bd.bd_b_id = bs.bs_id)
LEFT JOIN b_q_answers ba
ON (sh.sd_s_id = ba.ba_s_id)
LEFT JOIN bsquestions bq
ON (bq.bq_id = ba.ba_q_id)
LEFT JOIN multiples m
ON (ba.ba_m_id = m.m_id)
LEFT JOIN users u
ON (u.us_id = bd.bd_d_id)
LEFT JOIN profiles p
ON (p.p_u_id = bd.bd_d_id)
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
WHERE sd_sub = '1' AND bq_text <> 'Date' AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
That works perfectly, the problem is it has to use sub-queries which as time goes by will get less efficient.
I'm just wondering if there is a better more efficient way to do that summed field without it.
Presumably the subquery you're concerned about is the one in your toplevel SELECT.
That is easy to refactor so it won't get repeated.
Just JOIN it to the rest of the table. You'll want this sort of thing:
SELECT
bq_text, ...
COUNT(ba_a) AS ba_aC,
countup.countup AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
...
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
JOIN (
SELECT COUNT(*) AS countup , sd_b_id
FROM board_done_sheet
WHERE sd_sub = 1
GROUP BY sd_b_id
) AS countup ON countup.sd_b_id = bs.bs_id
WHERE sd_sub = '1'
AND bq_text <> 'Date'
AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
The countup subquery generates a summary table of counts and ids, and then joins it to the other tables.
A JOIN cascade of this complexity may become inefficient for other reasons as your table grows if you don't structure your indexes correctly.