Update MYSQL Table from multiple rows in another table - mysql

I'm trying to update table yy from table xx results by doing sum.
For example (syntax is abstract):
update table_yy
set sum_of_x_and_y = (
(select sum(row_x) from table_xx where class_id=1)
+
(select sum(row_y) from table_xx where class_id=1) )
Table xx
row_id class_id row_x row_y
1 1 4 5
2 1 5 6
3 2 6 7
4 1 7 8
Table yy
class_id sum_of_x_and_y
1 35
2 13
but instead of setting the class_id manually, I would love to do something like inner-join update, but I'm working with 15k+ of records.

Here is a query that should do the job
UPDATE table_yy, (
SELECT class_id, SUM(table_xx.row_x + table_xx.row_y) AS sum_of_x_and_y
FROM table_xx
GROUP BY table_xx.class_id
) AS table_sum
SET table_yy.sum_of_x_and_y = table_sum.sum_of_x_and_y
WHERE table_yy.class_id = table_sum.class_id

Your approach is fine. You just want a correlated subquery:
update table_yy yy
set sum_of_x_and_y = (select sum(xx.row_x) + sum(xx.row_y)
from table_xx xx
where xx.class_id = yy.class_id
);
Under many circumstances, this will have better performance, particularly if you have an index on table_xx(class_id).

Related

how can I order my SQL query by the next-in-line parent's ID?

I have a table called stages like this:
stageID
stage
parentStageID
1
Stage1
NULL
2
Stage2
3
3
Substage1
1
4
Stage3
2
The parentStageID references the stageID of its parent in the same table. I'm trying to write a query that selects everything in the table and sorts them by order of the next child in line. The NULL parentStageID being the first in the sequence, followed by the next stage with parentStageID equal to the last stageID.
The ordered table results like this:
stageID
stage
parentStageID
1
Stage1
NULL
3
Substage1
1
2
Stage2
3
4
Stage3
2
I'm not entirely sure how to go about doing this, but from other similar stack posts I was trying to do this with:
SELECT * FROM stages ORDER BY COALESCE(`parentStageID`, `stageID`), `parentStageID` IS NOT NULL, `stageID`;
Here I have this small Demo on SQL fiddle
as you can see this query is resulting as:
stageID
stage
parentStageID
1
Stage1
NULL
3
Substage1
1
4
Stage3
2
2
Stage2
3
Appreciate any ideas on the type of query I need for this!
You can use a recursive cte:
with recursive d(id, stage, pid) as (
select * from demo where parentstageid is null
union all
select d2.* from d d1 join demo d2 on d1.id = d2.parentstageid
)
select * from d;
Output:
id
stage
pid
1
Stage1
null
3
Substage1
1
2
Stage2
3
4
Stage3
2
Hi this is quite a tricky question, your data is similar to a companies employee data we can say for example:
Employee 1 has Employee 3 as his higher up
Employee 3 is the highest level in company
Employee 2 has Employee 1 as his higher up
what you need is to order employee based on their level in company, highest first then level below it and so on
Employee 3
Employee 1 , Employee 3
Employee 2 , Employee 1
Considering this above scenario, I tried to create a T-SQL code hope it helps:
-- Getting all data in seprate table
-- Indi column added to tell if that record is processed or not for ordering
-- Ord column added to give order for final output
select *,ParentStageid as dummy, 0 ord, 0 indi
into #test
from stage
Declare #pstageID int = 0
Declare #order int = 1
-- while loop which will run through each record
while exists(select * from #test where indi = 0)
begin
update #test
set ord = #order, indi = 1 ,#pstageID = stageID
where dummy is null and indi = 0
Update #test
set dummy = null
where parentStageID = #pstageID
set #order = 1 + #order
end
-- Final Output as asked
select * from #test
order by ord
Output:
This code might not be best for huge data, but it will give the expected output.

Avoid duplicates on MySQL update

I have a many-to-many relation table like this
element_a
element_b
1
2
1
3
2
1
2
3
3
1
3
3
I want to replace element_a with id 2 by id 1
UPDATE mytable x
SET x.element_a = 1
WHERE x.element_a = 2;
Since there is an unique index on (element_a, element_b ), this will result with duplicates error.
How can I execute my query without MySQL Error 1062 ?
You can use an update with LEFT JOIN:
UPDATE mytable x
LEFT JOIN mytable t ON t.element_b = x.element_b AND 1 = t.element_a
SET x.element_a = 1
WHERE
x.element_a = 2 AND t.element_a IS NULL
If t.element_a IS NOT NULL then pair element_a, element_b already exists in your table. Thus adding t.element_a IS NULL in the WHERE clause prevents UPDATE in case of duplicates.
Demo here

SQL Query, how to select a interval where the next value is current value +1, identifying the next gap and leave everything else untouched?

I'm making a program on java using sql querys and i'd like to update a sequence of ids adding 1 to each, but only in the sequence interval.
Let's say i have a table like this:
1 - a | 2 - b | 3 - c | 5 - e | 6 - f
And i'd like to "push" a's ID and subsequents forward by 1, but only while the difference between one another is still 1. The result would be like this:
2 - a | 3 - b | 4 - c | 5 - e | 6 - f
I know it is possible to do programatically, but is there a way to do this with SQL querys? If not, what would be the best way to do this?
Thanks in advance.
Edit: Found the answer thanks to Thorsten Kettner, my query ended up like this:
update pair set id = id + 1
where id >= 1
and id <
(
select min(id)
from (select * from pair) as gap
where gap.id > 1 and not exists
(
select *
from (select * from pair) as oneless
where oneless.id = gap.id - 1
)
)
order by id desc
If you know where the gap is that you want closed (ID 4 in your case) use this:
update mytable set id = id + 1 where id < 4;
If you don't know where the gap is, find it:
select min(id) - 1
from mytable
where not exists
(
select *
from mytable oneless
where oneless.id = mytable.id - 1
);
We can combine both statments now to do the update:
update mytable set id = id + 1
where id <
(
select min(id) - 1
from mytable
where not exists
(
select *
from mytable oneless
where oneless.id = mytable.id - 1
)
);
Let's call your table Pair and the two columns Key and Value. Your query would be something like this:
update p1
set Key = p1.Key + 1
from Pair as p1
inner join Pair as p2
on p2.Key = p1.Key + 1
PS. I'm assuming your result has a typo because after the update, f should have a value of 7.

Count first occurence with column value ordered by another column

I have an assigns table with the following columns:
id - int
id_lead - int
id_source - int
date_assigned - int (this represents a unix timestamp)
Now, lets say I have the following data in this table:
id id_lead id_source date_assigned
1 20 5 1462544612
2 20 6 1462544624
3 22 6 1462544615
4 22 5 1462544626
5 22 7 1462544632
6 25 6 1462544614
7 25 8 1462544621
Now, lets say I want to get a count of the rows whose id_source is 6, and is the first entry for each lead (sorted by date_assigned asc).
So in this case, the count would = 2, because there are 2 leads (id_lead 22 and 25) whose first id_source is 6.
How would I write this query so that it is fast and would work fine as a subquery select? I was thinking something like this which doesn't work:
select count(*) from `assigns` where `id_source`=6 order by `date_assigned` asc limit 1
I have no idea how to write this query in an optimal way. Any help would be appreciated.
Pseudocode:
select rows
with a.id_source = 6
but only if
there do not exist any row
with same id_lead
and smaller date_assigned
Translate it to SQL
select * -- select rows
from assigns a
where a.id_source = 6 -- with a.id_source = 6
and not exists ( -- but only if there do not exist any row
select 1
from assigns a1
where a1.id_lead = a.id_lead -- with same id_lead
and a1.date_assigned < a.date_assigned -- and smaller date_assigned
)
Now replace select * with select count(*) and you'll get your result.
http://sqlfiddle.com/#!9/3dc0f5/7
Update:
The NOT-EXIST query can be rewritten to an excluding LEFT JOIN query:
select count(*)
from assigns a
left join assigns a1
on a1.id_lead = a.id_lead
and a1.date_assigned < a.date_assigned
where a.id_source = 6
and a1.id_lead is null
If you want to get the count for all values of id_source, the folowing query might be the fastest:
select a.id_source, count(1)
from (
select a1.id_lead, min(a1.date_assigned) date_assigned
from assigns a1
group by a1.id_lead
) a1
join assigns a
on a.id_lead = a1.id_lead
and a.date_assigned = a1.date_assigned
group by a.id_source
You still can replace group by a.id_source with where a.id_source = 6.
The queries need indexes on assigns(id_source) and assigns(id_lead, date_assigned).
Simple query for that would be
check here http://sqlfiddle.com/#!9/8666e0/7
select count(*) from
(select * from assigns group by id_lead )t
where t.id_source=6

row dependant variables in mysql query

I have a mysql database as follows. I am using it with phpmyadmin.
id time_came time_exit
0 2 3
1 3 5
5 5 1
7 1 10
9 1 8
I want another column as "wait" with the following logic,
foreach(i in time_came){
wait=count(time_came<i&&i<time_exit)
}
So then each column has a "wait" value too. I can do this with php. But I need to do this with mysql. I am confusing because "i" is varying for each row?
Thanks in advance.
Is this what you want?
select t.*,
(select count(*)
from table t2
where t2.time_came between t.time_came and t2.time_came < t.time_exit
) as wait
from table t;
EDIT:
To do the update, you need to use join:
update table t join
(select t.id,
(select count(*)
from table t2
where t2.time_came between t.time_came and t2.time_came < t.time_exit
) as wait
from table t
) as newval
on t.id = newval.id
set t.wait = newval.wait