Choose between two MySQL select queries based on mySQL IF-ELSE conditions - mysql

I am creating a data analytics dashboard.I pass a parameter named channel_param to MySQL data-source.
I want to add an if statement in this query that first checks if the channel_param parameter value is equal to "ALL"
In case of "ALL", the following query should execute :
SELECT
c.CountryCode, COUNT(f.`country_code_id`) AS view_count
FROM
fact_access_logs_views f
JOIN dim_country_code c ON f.`country_code_id` = c.`country_code_id`
JOIN dim_time_access d ON f.`access_time_id` = f.`access_time_id`
JOIN dim_channel chn ON f.`channel_id` = chn.`channel_id
In case of any other value, this query should execute:
SELECT
c.CountryCode, COUNT(f.`country_code_id`) AS view_count
FROM
fact_access_logs_views f
JOIN dim_country_code c ON f.`country_code_id` = c.`country_code_id`
JOIN dim_time_access d ON f.`access_time_id` = f.`access_time_id`
JOIN dim_channel chn ON f.`channel_id` = chn.`channel_id`
WHERE
chn.`shortname_chn` = ${channel_param}
How can I achieve this ?

This is how I solved the problem, using SQL CASE expression.
SELECT c.CountryCode, COUNT(f.`country_code_id`) AS view_count FROM fact_access_logs_views f
JOIN dim_country_code c ON f.`country_code_id` = c.`country_code_id`
JOIN dim_time_access d ON f.`access_time_id` = f.`access_time_id`
JOIN dim_channel chn ON f.`channel_id` = chn.`channel_id`
WHERE chn.`shortname_chn` LIKE
CASE WHEN
${channel_param} = "ALL" THEN '%%' ELSE ${channel_param}
END
I hope this answer helps people facing the same confusion in future.

Related

Using group_concat with update statement in MySql

I am trying to execute the below update query using GROUP_CONCAT but it is failing.
Can anyone kindly help me in correcting it, moreover the statement must always start with the “update” keyword is the catch here as well.
UPDATE firstEntry f,
objects o,
titlement_values e
SET e.customattribute12 = (
SELECT GROUP_CONCAT(DISTINCT o.minvalue)
WHERE f.ldkey = o.ld_key
AND o.TITLE_VALUEKEY = e.TITLE_VALUEKEY
AND e.TITLE_VALUE = 'ZD%'
AND f.ldkey = 13
AND e.TITLEMENTTYPEKEY = 13
GROUP BY e.title_value)
I tried to execute the below query as well but no luck in it as well:
UPDATE firstEntry f,
objects o,
titlement_values e
SET e.customattribute12 = minval
FROM (SELECT GROUP_CONCAT(DISTINCT o.minvalue) AS minval,
e.title_value
WHERE f.ldkey = o.ld_key
AND o.TITLE_VALUEKEY = e.TITLE_VALUEKEY
AND e.TITLE_VALUE = 'ZD%'
AND f.ldkey = 13
AND e.TITLEMENTTYPEKEY = 13
GROUP BY e.title_value)
Here is the table result of using select statement on joining the 3 tables mentioned in the query
group_concat
e.titlement_value
A1,A2,A3
Zd_A
A1,B2
Zd_B
Now i need to take the value of this group_concat and update it in the column e.customattribute12 as shown
e.titlement_value
e.customattribute12
zd_A
A1,A2,A3
zd_B
A1,B2
You need to rewrite your update as MySQL doesn't support FROM clauses in UPDATE statements: a correlated subquery will do the trick, as it returns only one scalar value.
Also JOIN operations are around for 30 years and are established standard, you should switch also to it.
with the problem you mentioned in the comment.
mjava.sql.BatchUpdateException: You can't specify target table 'e' for update in FROM claus
it os MySQL error 1063
MySQL doesn't like when the updated table is in somewhere used again, we can avoid that with a trick seen below, as we force MySql to produce a new temporary table
UPDATE titlement_values e
SET
e.customattribute12 = (SELECT
GROUP_CONCAT(DISTINCT o.minvalue)
FROM
firstEntry f
INNER JOIN
objects o ON f.ldkey = o.ld_key
INNER JOIN
(SELECT * FROM titlement_values) e1 ON o.TITLE_VALUEKEY = e1.TITLE_VALUEKEY
WHERE
e1.TITLE_VALUE LIKE 'ZD%' AND f.ldkey = 13
AND e1.TITLEMENTTYPEKEY = 13
AND e1.title_value = e.title_value)
Once you are able to make sure that the subquery works correctly, try applying the join between your table to be updated and your crafted subquery, on matching "title_value" values.
UPDATE titlement_values
INNER JOIN (SELECT GROUP_CONCAT(DISTINCT o.minvalue) AS minval,
e.title_value
FROM firstEntry f
INNER JOIN objects o ON f.ldkey = o.ld_key
INNER JOIN titlement_values e ON o.TITLE_VALUEKEY = e.TITLE_VALUEKEY
WHERE e.TITLE_VALUE LIKE 'ZD%'
AND f.ldkey = 13
AND e.TITLEMENTTYPEKEY = 13 ) cte
ON titlement_values.title_value = cte.title_value
SET customattribute12 = cte.minval

cakePHP - Join with conditional virtual field

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')

How can I update some rows using an inner join in SQL in a way which will work on both mysql and postgres?

I have this SQL which updates rows on MySQL, but I need to rewrite it so that it will work on PostgreSQL as well. I'm aware that I can make it work for PostgreSQL using a different syntax, but I need one statement which will work for both systems.
UPDATE {coursework_feedbacks} AS f
INNER JOIN {coursework_submissions} AS s
ON f.submissionid = s.id
INNER JOIN {coursework} c
ON s.courseworkid = c.id
SET f.stage_identifier = 'assessor_1'
WHERE f.ismoderation = 0
AND f.isfinalgrade = 1
AND c.numberofmarkers = 1
As this particular case can be phrased with a correlated subquery, you can just write:
UPDATE {coursework_feedbacks} AS f
SET f.stage_identifier = 'assessor_1'
WHERE f.ismoderation = 0
AND f.isfinalgrade = 1
AND EXISTS (
SELECT 1
FROM {coursework_submissions} AS s
INNER JOIN {coursework} c ON s.courseworkid = c.id
WHERE f.submissionid = s.id AND c.numberofmarkers = 1
);
but in the more general case where that isn't true (say, where you need to update a value based on the result of the join) I don't know if there is a portable, efficient way.

Rails - How to force associations to use alias table name

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.

Referencing (Using an alias) the value from nested MySQL query in an outer conditional statement

I'm using a nested query to get the value I need from a table that I then need to use in a conditional statement, however, every time I try this I keep on getting an error saying unknown column (format) in the field list
SELECT
(SELECT format FROM competition_stages WHERE comp_id = "5" AND rid = "24") AS format,
a.tie_id, b.name AS team_a, b.team_id AS team_a_id, c.name AS team_b, c.team_id AS team_b_id, SUM(e.bonus) AS team_a_bonus, SUM(f.bonus) AS team_b_bonus,
SUM(CASE
WHEN (a.team_a = e.team_id AND format = "0") THEN e.score
END) as team_a_agg,
SUM(CASE
WHEN (a.team_b = f.team_id AND format = "0") THEN f.score
END) as team_b_agg
FROM competition_tie a
INNER JOIN teams b ON (a.team_a = b.team_id)
INNER JOIN teams c ON (a.team_b = c.team_id)
LEFT JOIN fixtures d ON (a.tie_id = d.tie_id)
LEFT JOIN fixture_scores e ON (d.fx_id = e.fx_id AND a.team_a = e.team_id)
LEFT JOIN fixture_scores f ON (d.fx_id = f.fx_id AND a.team_b = f.team_id)
WHERE a.comp_id = "5" AND a.rid = "24" AND a.season_id = "5"
GROUP BY a.tie_id
ORDER BY a.tie_id ASC
I can get the value of the format column in my results when I go through them but it just seems I can't use it within my query to use in.
Thanks for your help!
Instead of using a subquery, simply join the competition_stages table to your query so that you can reference the format column directly. Assuming there is no appearant relation between the competition_stages table and the other tables in the query (at least not from the information on hand), you can just join the table using the two conditions you specified if these conditions would only yield 1 result in the competition_stages table. Something like this:
SELECT cs.format, a.tie_id, ....
FROM competition_tie a ...
INNER JOIN competition_stages cs ON cs.comp_id = "5" AND cs.rid = "24"