GUJ Discussões   :   últimos tópicos   |   categorias   |   GUJ Respostas

Ter tabela com nomes mais usados nos registros das outras tabelas?

banco
Tags: #<Tag:0x00007f4d9cf950d8>

#1

Olá. Vendo esse título pode parecer meio sem sentido, mas é realmente isso que eu quero fazer. Eu preciso ter uma tabela atualizada no Mysql com os nomes mais utilizados nos registros das outras tabelas. Quando eu digo nomes, não falo do que está no campo “nome” da tabela usuários, mas palavras iniciando com letras maiúsculas em campos text. Alguém tem alguma ideia de como fazer isso? Existe algum tipo de “contains” no campo text como o da String no Java?


#2

Acho que você vai precisar de um evento agendado no banco, tendo sua lógica para selecionar as palavras mais usadas e inserí-las na tabela destino.

Você pode configurar um evento para rodar diariamente por exemplo, todo dia na madruga ou semanalmente, etc…


#3

Que legal, eu arrumei uma maneira de suprir de alguma forma esse problema direto na aplicação, pois achava que ninguém mais iria responder, mas eu realmente prefiro fazer como eu citei.
Esse negócio para monitorar não é o problema, posso fazer até um trigger mesmo, o problema é “dizer o que é mais usado”.


#4

Ai onde cabe você analisar o que é viável, imagino que o preenchimento dessa tabela pela aplicação não faria muito sentido, seria uma responsabilidade a mais para a linguagem, acho que um evento agendado na madruga já te mostra pela manhã as palavras mais utilizadas sendo pesquisadas pela própria base…

Ai a aplicação só precisa fazer um select e mostrar na tela se for o caso…

Vai se acostumando com o termo “Regra de Negócio”…


#5

Sim, esse era meu objetivo desde o início, mas meu problema é a lógica de como fazer isso porque eu não tenho nem ideia. Só sei o básico de SQL, e ATÉ ONDE EU SEI não dá pra fazer esse tipo de estrutura.


#6

Dá sim, usando count() e group by por exemplo as palavras que aparecerem no mínimo 50x… você já pode mandar direto para a tabela de destino assim…

INSERT INTO mais_usadas (palavra, qtd) SELECT palavra, COUNT(*) AS total FROM tabela 
GROUP BY palavra HAVING COUNT(*) >= 50;

Eu só não me recordo se é possível ordenar pela quantidade maior…

... ORDER BY COUNT(*) DESC;

A questão principal para te atender não nem a lógica, mas em que período isso será feito, já que você precisa sempre inserir palavras novas etc, mas isso já pode ser sanado com o evento…

A partir daí jovem, sua imaginação é o limite…


#7

Daí em diante é fácil. Esses eventos agendados não tem muito segredo, são como triggers, mas o problema é nessa parte:

ON SCHEDULE cronograma

Qual seria a sintaxe do intervalo? Como eu posso definir para ser chamado sempre a meia noite por exemplo? Eu coloco 00:00?


#8

Há várias formas de agendar

https://dev.mysql.com/doc/refman/5.7/en/create-event.html

Mas creio que isso possa servir…

ON SCHEDULE EVERY 24 HOUR 

Com relação a comparação com trigger, evite, sabemos que triggers, functions, procedures e schedulers basicamente são funções/rotinas que o banco nos dispõe, mas a diferença principal é que trigger é chamada/executada a cada registro que entra na tabela por isso citei a questão de desempenho em outro post…


#9

Cara, valeu mesmo, isso está me ajudando muito. Eu estou implementando no meu projeto, porém eu me deparei com um problema. É bem complicadinho, acho que não vou conseguir explicar bem, por isso, vou mostrar:
A tabela onde eu estou realizando essa “varredura” pelas palavras mais usadas se chama itens, eu estou buscando no campo conteúdo:

Porém cada ITEM, tem seu usuário:

Eu quero que essas palavras fiquem em uma tabela separada como tu mostrou, PORÉM, a tabela das palavras deve ter um relacionamento DE UM PRA MUITOS com a tabela usuários.
Resumindo: Essa “varredura” deve ser feita na tabela itens, porém devem ser definidos a cada palavra os usuários que contém ela.

Porém a única maneira que eu encontrei de fazer isso seria um for each nos itens de cada usuário, porém como eu já disse, eu tenho muita pouca experiência com a sintaxe do SQL, não sei como é a estrutura do for each no Mysql e não estou conseguindo implementar. Sabe me dar um exemplo?


#10

Quanto ao foreach em mysql, chama-se cursor, mas evite-o o desempenho fica prejudicado…

Não entendi muito bem o relacionamento entre as tabelas, quem é pai de quem ai?


#11

Muitos usuários podem ter uma palavra. O pai seria o usuário certo?


#12

Não necessariamente, você está com o conceito de “uma palavra” fixo na cabeça, mas para a base de dados nã faz diferença, a mesma palavra várias vezes continua sendo registros diferentes pegou?

Me refiro ao relacionamento de campos mesmo, ou não existe?

Por exemplo, na tabela itens existe algum campo (chave estrangeira) que indica qual seu usuário?

Se sim esse campo é um int representando um código, é o cpf do usuário, rg ou o quê?

Para facilitar a comunicação, o workbench dispõe de uma ferramenta que faz a engenharia reversa da base, ou seja, traz do físico para o papel e monta um MER (modelagem entidade e relacionamento), e dependendo de como você configurou as tabelas, traz até os relacionamentos…

Pesquise e se conseguir gerar tira um print e manda pra gente ver e ter uma visão “panorâmica” do seu projeto…


#13

É basicamente o que eu estou fazendo. Me desculpe eu coloquei errado, não é uma relacionamento de UM PRA MUITOS, e sim de MUITOS PRA MUITOS, eu me enganei na hora, mas agora tu vai entender. Mas antes de tudo eu acho que devo explicar o sentido disso, porque eu achei desnecessário explicar no início do tópico, mas eu estou tentando ter uma tabela com o que os usuários gostam de acordo com o que eles colocam no campo conteúdo do item, como o nome de uma banda por exemplo, sacas? Mas gostaria que fosse tudo automático, e a razão pela qual eu estou fazendo esse relacionamento é para que quando dois ou mais usuários tenham o mesmo gosto, não hajam registros duplicados.


#14

O que você quer é alem de pegar os conteúdos mais citados, os usuários amarrados certo?

A primeira coisa a se fazer, já que você não pode ter duplicidade, na tabela de destino, chamarei de mais_usadas ok?

Nas mais_usadas, dentro do scheduler, precisa limpar a tabela completamente e reinserir a busca…

truncate table mais_usadas;

Isso fara uma limpa geral na tabela e irá resetar o AUTO_INCREMENT caso ela possua… bem melhor que delete from… nesse caso…

Após, use a query +/- parecida com o que te mostrei…

Após essa inserção, precisa ter a tabela por exemplo eleitores com campo item e usuario como na tabela itens…

Agora irá consultar as mais_usadas junto da itens para pegar os usuários e colocar em eleitores…

INSERT INTO eleitores (muid, item, usuario) 
SELECT m.id, i.id, i.usuario FROM mais_usadas AS m
INNER JOIN itens AS i ON i.conteudo = m.palavra

Perceba que na tabela eleitores, coloquei o campo muid, isso para relacioná-lo com a tabela mais_usadas, além de também relacionar com a tabela item e usuario, assim você consegue fazer join de qualquer uma delas…

Por exemplo, se sua aplicação precisa mostrar os eleitores + mais usadas, basta juntar usuarios + eleitores + mais_usadas e assim por diante…

Espero ter ajudado…


#15

Tipo assim?

delimiter $$
CREATE EVENT definir_gostos ON SCHEDULE EVERY 24 HOUR DO
BEGIN
SELECT INSERT INTO gostos(palavra) SELECT palavra, COUNT(*) AS conteudo FROM itens 
ORDER BY COUNT(*) DESC;
INSERT INTO usuario_gosta(muid, usuario, gosto) 
SELECT m.id, i.usuario, i.conteudo FROM gostos AS m
INNER JOIN itens AS i ON i.conteudo = m.gosto
END$$
delimiter ;

O Workbench diz que tem um erro de sintaxe, porém eu não estou percebendo, sabe me dizer qual é?


#16

Pode ser nesse trecho…

SELECT INSERT INTO gostos(palavra) SELECT palavra, COUNT(*) AS conteudo FROM itens 
ORDER BY COUNT(*) DESC;

Deveria ser assim…

INSERT INTO gostos(palavra, qtd) SELECT palavra, COUNT(*) AS conteudo FROM itens 
ORDER BY COUNT(*) DESC;

Funciona assim, para cada campo do insert que voce declara, precisa selecionar um valor compativel, você selecionou o COUNT(*), mas ele não vai para campo nenhum da tabela… entendeu?

Você também não é obrigado a usar o count(*), pois o que interessa é o argupamento, pode fazer assim também…

INSERT INTO gostos(palavra) SELECT palavra FROM itens 
ORDER BY COUNT(*) DESC;

#17

Não há mais erros, e eu criei o evento. Porém nada foi adicionado na tabela gostos. O evento é executado uma primeira vez antes, ou só 24 horas depois da sua criação? Ou tem algum erro aí que eu não tô vendo?


#18

Seguindo a lógica, irá rodar a cada 24h certo?

A ferramenta que você está usando não tem algum botão disponível para rodar o evento a qualquer hora como aquele trovãozinho do mysql workbench para executar queries por exemplo?

Talvez ele esteja contando 24h do horário que você criou o evento, vi na documentação alguns exemplos dessa forma…

SCHEDULE EVERY 24 HOUR STARTS '2017-03-09 00:00:00'

Se funcionar, ele irá rodar hoje a meia noite e a partir daí, 24h todo dia…

Outr coisa, verifique se a consulta está realmente trazendo registro na contagem, usando apenas isso…

SELECT palavra, COUNT(*) AS conteudo FROM itens 
ORDER BY COUNT(*) DESC;

Se o select trouxer registros, então você pode se convencer de que o job não rodou ainda…


#19

Eu uso o Workbench e o HeidSql, mas não vi nada do tipo.[quote=“LostSoldier, post:18, topic:343654”]
Talvez ele esteja contando 24h do horário que você criou o evento, vi na documentação alguns exemplos dessa forma…

SCHEDULE EVERY 24 HOUR STARTS ‘2017-03-09 00:00:00’

Se funcionar, ele irá rodar hoje a meia noite e a partir daí, 24h todo dia…
[/quote]

Okay, já atualizei a estrutura e criei os registros, assim que for executado eu retorno aqui e digo o que aconteceu.[quote=“LostSoldier, post:18, topic:343654”]
Outr coisa, verifique se a consulta está realmente trazendo registro na contagem, usando apenas isso…

SELECT palavra, COUNT() AS conteudo FROM itens
ORDER BY COUNT(
) DESC;

Se o select trouxer registros, então você pode se convencer de que o job não rodou ainda…
[/quote]

Eu deveria substituir “palavra” por conteudo?


#20

O que lhe mostrei desde o começo foram exemplos, você precisa adequar as suas necessidades…

Percebi que você tinha nomeado o COUNT(*) AS conteudo… isso vai te trazer um int com a quantidade de palavras/conteudo como você chama…

o AS a gente usa em consultas para exibição dos dados, no seu caso não é necessário… volto a frisar sobre essa regra…

Se sua tabela gostos não tem um campo para guardar a quantidade que mostrei, seu SQL então precisa ser assim…

SELECT palavra FROM itens ORDER BY COUNT(*) DESC;

Outra coisa, agora que percebi que você não está agrupando o conteúdo (onde eu chamo de palavra) o ideal para você seria…

SELECT conteudo FROM itens GROUP BY conteudo;

Seja sincero, você está fazendo as queries totalmente no escuro não é?

Você realmente entendeu o significado do

 COUNT(*)

e do

GROUP BY conteudo

e do

ORDER BY COUNT(*) DESC?