MySQL / SQL: Atualização com subconsulta correlacionada da própria tabela atualizada
-
22-07-2019 - |
Pergunta
Eu tenho uma pergunta genérica que vou tentar explicar usando um exemplo.
Say Eu tenho uma tabela com os campos: "id", "nome", "categoria", "aparências" e "ratio"
A idéia é que eu tenho vários itens, cada uma relacionada a uma única categoria e "aparecer" várias vezes. O campo de relação deve incluir a percentagem de aparições de cada item em relação ao número total de aparições de itens na categoria.
Em pseudo-código que eu preciso é o seguinte:
-
Para cada categoria
encontrar a soma total das aparências para itens relacionados a ela. Por exemplo, pode ser feito com (select sum("appearances") from table group by category
) -
Para cada item
definir o valor da relação de aparências do item dividido pela soma encontrada para a categoria acima
Agora eu estou tentando conseguir isso com uma consulta atualização única, mas não consigo fazê-lo. O que eu pensei que eu deveria fazer é:
update Table T
set T.ratio = T.appearances /
(
select sum(S.appearances)
from Table S
where S.id = T.id
)
Mas MySQL não aceita o alias T na coluna de atualização, e eu não encontrou outras maneiras de conseguir isso.
Todas as idéias?
Solução
Após as duas respostas que recebi (nenhum dos quais estava completo assim que eu escrevi o meu próprio), o que acabou fazendo é o seguinte:
UPDATE Table AS target
INNER JOIN
(
select category, appearances_sum
from Table T inner join (
select category as cat, sum(appearances) as appearances_sum
from Table
group by cat
) as agg
where T.category = agg.cat
group by category
) as source
ON target.category = source.category
SET target.probability = target.appearances / source.appearances_sum
Ele funciona muito rapidamente. Eu também tentei com subconsulta correlacionada mas foi muito mais lento (ordens de magnitude), então eu estou furando com a junção.
Outras dicas
Use junta-se logo após UPDATE: Reference Manual - 13.2.11 ATUALIZAÇÃO Sintaxe
para ATUALIZAÇÃO table1 junção interna table2 on .... conjunto table1.foo = valor onde table2.bla = someothervalue
Com este tipo de coisas, sempre olhar para o manual. O MySQL tem um manual de referência adequada, por isso não deve ser tão difícil para obter a sintaxe direita;)
Esta é a forma como é feito em mssql, acho mysql é o mesmo ou similar:
create table T (id int, ratio float, appearances int)
insert T values (1, null, 2)
insert T values (1, null, 3)
update T
set ratio = cast(appearances as float)/ agg.appearancesSum
from T join (
select id, sum(appearances) as appearancesSum
from T
group by id
) as agg on t.id = agg.id