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

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…

1 curtida

É 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.

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…

1 curtida

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 é?

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;
1 curtida

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?

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…

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?

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?
1 curtida

Mais ou menos. Eu tenho bastante experiência com SQL, porém isso que estou tentando fazer é bem avançado pra mim, e mesmo com os seus exemplos, e mesmo a sintaxe do SQL ser bem clara, estou sim com algumas dificuldades para entender. Mas vamos por partes então.

Vamos ver o que eu entendi nessa parte. Tu está pegando o campo conteúdo pela ordem de repetição deles? O que eu ainda não entendi é que o campo é um texto, e eu quero que essa ordem seja dada pelas palavras dos mesmos.

Eu realmente não entendi essa parte.[quote=“LostSoldier, post:20, topic:343654”]
COUNT(*)
[/quote]

É uma função que retorna a quantidades de registros do select certo?

Já vi muito sobre o GROUP BY, mas nesse caso, eu não estou entendendo.[quote=“LostSoldier, post:20, topic:343654”]
ORDER BY COUNT(*) DESC?
[/quote]

Tu está ordenando os registros pelo os que se repetem certo?

Essa sua bastante experiência com SQL precisa ser bem treinada :joy:

Brincadeiras a parte, vamos la…

Quando se usa agrupamento GROUP BY, você quer deixar em uma unica linha, várias encontradas, um exemplo, na tabela itens você tem conteudos com os nomes Rock 2 vezes e MPB 3 vezes

Pois bem, se você usar um select comum… Você terá varias linhas “repetidas” correto?

SELECT conteudo FROM itens;

Rock
MPB
Rock
MPB
MPB

Com o agrupamento fica assim:

SELECT conteudo FROM itens GROUP BY conteudo;

Rock
MPB

Quando se usa COUNT(*) em agrupamentos, alem de juntar os repetidos, ele conta quantas repetições encontrou para aquele agrupamento…

SELECT conteudo, COUNT(*) repeticoes FROM itens GROUP BY conteudo;

Rock, 2
MPB, 3

Como havia lhe falado lá em cima, não me recordo se o mysql permite funções como COUNT em declarações como ORDER BY, mas de todo modo se eu quiser ordenar a consulta pela quantidade de repetições do maior para o menor ficaria…

SELECT conteudo, COUNT(*) repeticoes FROM itens GROUP BY conteudo 
ORDER BY COUNT(*) DESC;

MPB, 3
Rock, 2

Clareou mais agora as idéias?

Agora encaixando essa lógica no seu problema, você tem a tabela gostos e digamos que além dos conteudos, queira gravar também quantas vezes aquele gosto foi citado, é ai que você precisa criar uma coluna int para guardar o COUNT que eu tinha nomeado como qtd e você mudou para conteudo, complicadndo mais ainda o entendimento :joy: pegou?

E pra finalizar, a quantidade de colunas que você usar no select, será o “values” para o insert into gostos, ou seja, se selecionei uma coluna, devo usar apenas uma no insert, etc…

1 curtida

Agora sim eu entendi toda a estrutura, e estou testando todos os comandos do evento, porém como eu disse, eu preciso saber as PALAVRAS, e com o SELECT, eu estou recebendo as frases. Usando o mesmo exemplo seu…Se ao Rock e MPB estiverem dentro de frases, e tu quiser fazer esse mesmo procedimento?

Essa solução irá agrupar e mandar os valores que estiverem no campo conteudo e forem iguais, se você guarda frases ao invés de termos aí complica bem… para o que você precisa será algo bem mais complexo e eu não faço idéia, talvez você consiga algum norte pesquisando sobre BI

E discordo, em nenhum momento você citou que guardava frases no campo conteudo…

Se tu não sabe, imagina eu :joy:. Bem, eu tenho uma ideia, mas não sei aplicar no Mysql, talvez tu saiba. Seria possível fazer um split utilizando o caractere " " e salvar cada palavra em uma tabela temporária? Assim basta eu realizar esse procedimento nessa tabela certo?

Sobre split, algo nesse post

Agora tente adaptar à sua necessidade… boa sorte ai

Já vai pesquisando sobre subqueries também, talvez possa precisar, ou usar a tabela temporária pode ser uma saída…

1 curtida

Eu consegui dessa maneira:

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');
       
SELECT SPLIT_STR((SELECT group_concat(conteudo SEPARATOR ' ') from itens), ' ', 1);

Porém a cada SELECT ele retorna um resultado do SPLIT. Para retornar tudo e criar a tabela temporária, eu precisaria ficar incrementando esse index aí. Sabe como eu posso fazer isso? Desde já peço desculpas pela ignorância, mas estou mesmo com dificuldade de me adaptar a essa sintaxe. E eu tenho medo de mexer com loops e provocar algum problema de performance.

Exemplo na net é o que não falta…

Aproveita pra ir treinando SQL, logo você fica craque e te garanto, é só assim que se aprende.

Quanto a usar loops em base de dados, como falei antes, evite ao máximo, diferente das linguagens, a base sofre com performance principalmente se usar cursores…

Eu já vi esse exemplo várias vezes, mas não consegui fazer nesse meu código.

Eu não queria usar, mas não vejo outra alternativa. Aliás, eu tentei e não deu certo. Vou pesquisar mais sobre cursores e tentar implementar então.

Pronto. Consegui fazer o split e adaptei tudo a minha necessidade. Existe um pequeno bug no split, mas isso eu resolvo depois. Vamos por partes.

A função que eu utilizo para fazer o split:

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');

Eu criei um Stored Procedure para fazer o split e salvar na tabela temporária:

DELIMITER$$
CREATE PROCEDURE split_all(uid mediumint) begin
BEGIN
SET @grouped = (SELECT group_concat(conteudo SEPARATOR ' ') from itens WHERE usuario=uid);       
SET @countTotal = (select (LENGTH(@grouped) - LENGTH(replace(@grouped,' ',''))) / LENGTH(' '));
SET @i = 2;

CREATE TEMPORARY TABLE gostos_tmp SELECT SPLIT_STR(@grouped, ' ', 1);

WHILE @i <= @countTotal DO
	INSERT INTO gostos_tmp SELECT SPLIT_STR(@grouped, ' ', @i);
	SET @i = @increment+1;
END WHILE;
END$$
DELIMITER ;

E o corpo do evento ficou assim:

BEGIN
DECLARE uid MEDIUMINT DEFAULT 0;
DECLARE meu_cursor CURSOR FOR SELECT DISTINCT usuario FROM itens;
OPEN meu_cursor;
loop1: LOOP
	FETCH meu_cursor into uid;
	CALL split_all(uid);
	INSERT INTO gostos(gosto) SELECT 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 LOOP loop1;
END

Eu criei um Stored Procedure com o mesmo conteúdo do evento, para testar. E quando eu o chamo, recebo esta mensagem:

Alguém?