Using group_concat with update statement in MySql - 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

Related

Converting select statement to update (including exists & having)

Im trying to change some records in my database but sadly my sql knowledge is a bit limited. After googling and reading stuff online I have managed to write a select statement in which i can find the records that I want to update but i dont understand the logic to write the update statement to do it. I have to make several similar update statements so I hope this one I can figure out the rest myself
This is the select statement I have:
SELECT
MG.id,
MG.status,
MG.fin,
MG.execDateTime,
EXISTS
(
SELECT 1
FROM Mtask T
JOIN MTaskHis TH ON TH.t_id= T.id
WHERE T.tg_id = MG.id
AND YEAR(TH.dateTime) = 2019
) AS hasExecStart,
NMG.id,
NMG.execDateTime,
EXISTS
(
SELECT 1
FROM Mtask T
JOIN MTaskHis TH ON TH.t_id = T.id
WHERE T.tg_id = NMG.id
AND YEAR(TH.dateTime) = 2019
) AS hasExecNext
FROM Management_Group MG
JOIN MT_Groupman MTGM ON
MG.tgm_id = MTGM.id
LEFT JOIN Management_Group NMG ON MTGM.id =
NMG.tgm_id AND YEAR(NMG.execDateTime) = 2019
JOIN Management_Man MM ON MTGM.man_id = MM.id
JOIN Location L ON MM.location_id = L.id
WHERE L.org_id = 69
AND MG.stat != 'DELETED'
AND YEAR(MG.execDateTime) = 2018
AND MM.Type= 9
AND MG.fin != 1
AND EXISTS
(
SELECT 1
FROM Mtask T
WHERE T.tg_id = MG.id
AND T.stat = 'execution'
)
HAVING hasExecNext = 0 AND hasExecStart = 1
I know standard updates in sql:
UPDATE <TABLENAME>
SET <fieldName> = <value>
WHERE <conditons>
Except I do not know how to convert this select statement I have made into an update statement, reason for that is:
- Where do I put the exist alias in the update statement
- I also dont understand when or where to put all the JOINS in the from statement
- What about the HAVING
What is the best way to do joined updates like this?
In an UPDATE you can join the table you want to update to a sub-query that contains your current query.
UPDATE YourTable t
JOIN
(
<< add your query here >>
) q ON q.SomeKeyField = t.SomeKeyField
SET t.FieldName = q.FieldNameFromSubquery,
t.OtherFieldName = q.OtherFieldNameFromSubquery

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

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.

Incorrect SUM when using two LEFT JOINs and a GROUP BY

The following code returns an incorrect value for the sumHours field. It appears to prepare the sumHours field then once the GROUP BY runs, sum the sums together.
SELECT mmr_ID, mmr_projectName, SUM(mmr_hoursWorked.mmr_hoursWorked_hours) AS sumHours
FROM mmr
LEFT JOIN mmr_hoursWorked
ON mmr.mmr_ID = mmr_hoursWorked.mmr_hoursWorked_project AND mmr_hoursWorked.mmr_hoursWorked_mm = "P90826"
LEFT JOIN mmr_notes
ON mmr.mmr_ID = mmr_notes.mmr_notes_MMR_ref AND mmr_notes.mmr_notes_author = "P90826"
WHERE mmr_mmAssigned = "P90826" AND mmr_projectStatus != 1 OR mmr_notes.mmr_notes_author = "P90826" AND mmr_projectStatus != 1
GROUP BY mmr_ID
Actual Results
mmr_ID - 35
mmr_projectName - Project A
sumHours - 140.2
Expected Results
mmr_ID - 35
mmr_projectName - Project A
sumHours - 35.05
Due to JOIN statements combination of results are returned, so you should handle aggregates and joins separately. Try this:
SELECT t.*
FROM
(
SELECT mmr_ID, mmr_projectName, SUM(mmr_hoursWorked.mmr_hoursWorked_hours) AS sumHours
FROM mmr
LEFT JOIN mmr_hoursWorked
ON mmr.mmr_ID = mmr_hoursWorked.mmr_hoursWorked_project AND mmr_hoursWorked.mmr_hoursWorked_mm = 'P90826'
WHERE mmr_projectStatus != 1 AND mmr_mmAssigned = 'P90826'
GROUP BY mmr_ID, mmr_projectName, mmr_mmAssigned
) t
LEFT JOIN mmr_notes
ON t.mmr_ID = mmr_notes.mmr_notes_MMR_ref
WHERE mmr_notes.mmr_notes_author = 'P90826';
The issue was corrected by normalizing the database. The mmr_notes table was integrated into the mmr_hoursWorked table since it only had one unique field.

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.

MySQL select in update statement

This MySQL statement give me all id_duel_player for player with id_player=30 and it work fine.
SELECT b.id_duel_player
FROM duels a
INNER JOIN duel_player b
ON a.id_duel = b.id_duel
WHERE id_player = 30
UNION ALL
SELECT c.id_duel_player
FROM duel_player c
INNER JOIN
(
SELECT aa.*
FROM duels aa
INNER JOIN duel_player bb
ON aa.id_duel = bb.id_duel
WHERE bb.id_player = 30
) d ON c.id_duel = d.id_duel AND c.id_player <> 30
I want to make MySQL statement for UPDATE (fields from duel_player table) all of this id_duel_player that returns this select statement.
UPDATE duel_player
SET num = 2,
total = 5
WHERE (duel_player.id_duel_player = id_duel_player's from above SELECT statement)
I want most effective and fastest way to do this.
Thanks
For 200-400 rows it's likely fastest to create a temporary table with the results, and then do the UPDATE with a join:
CREATE TEMPORARY TABLE id_duel_players AS
SELECT b.id_duel_player as id FROM duels a ...
UPDATE duel_player
JOIN id_duel_players ON duel_player.id_duel_player = id_duel_players.id
SET num = 2,
total = 5
For smaller result sets you may find the IN operator sufficiently fast (... WHERE id_duel_player IN (SELECT ...)), but I've found it unreliable for result sets with hundreds of rows. (Unreliable = suddenly no matches are found, no idea why, I haven't investigated.)