Estou construindo um sistema de eventos personalizado e, se você tiver um evento repetido, parecido com este:
O evento A se repete a cada 4 dias, a partir de 3 de março de 2011
ou
O evento B se repete a cada 2 semanas na terça-feira, começando em 1 de março de 2011
Como posso armazenar isso em um banco de dados de uma maneira que simplifique a pesquisa. Não quero problemas de desempenho se houver um grande número de eventos e tenho que passar por todos ao renderizar o calendário.
database-design
calendar
Brandon Wamboldt
fonte
fonte
1299132000
é codificado? O que isso fará se eu precisar obter as datas de ocorrência e o usuário para a data final especificada?Respostas:
Armazenando padrões de repetição "simples"
Para o meu calendário baseado em PHP / MySQL, eu queria armazenar informações de eventos repetidos / recorrentes da forma mais eficiente possível. Eu não queria ter um grande número de linhas e queria pesquisar facilmente todos os eventos que ocorreriam em uma data específica.
O método abaixo é grande em armazenar repetir as informações que ocorre em intervalos regulares, como todos os dias, a cada n dias, cada semana, cada mês a cada ano, etc etc. Isto inclui todas as terças e quintas-feiras padrões tipo, bem como, porque eles são armazenados separadamente, todas as semanas, começando na terça-feira e toda semana, começando na quinta-feira.
Supondo que eu tenha duas tabelas, uma chamada
events
assim:E uma tabela chamada
events_meta
assim:Com repeat_start sendo uma data sem hora como carimbo de data / hora unix e repeat_interval, uma quantidade em segundos entre os intervalos (432000 é de 5 dias).
repeat_interval_1 acompanha o repeat_start do ID 1. Portanto, se eu tiver um evento que se repita toda terça e quinta-feira, o repeat_interval seria 604800 (7 dias) e haveria 2 repeat_starts e 2 repeat_intervals. A tabela ficaria assim:
Então, se você tiver um calendário que percorre todos os dias, capturando os eventos do dia em que está, a consulta terá a seguinte aparência:
Substituindo
{current_timestamp}
pelo carimbo de data e hora unix da data atual (menos a hora, os valores de hora, minuto e segundo seriam definidos como 0).Espero que isso ajude outra pessoa também!
Armazenando padrões de repetição "complexos"
Esse método é mais adequado para armazenar padrões complexos, como
Event A repeats every month on the 3rd of the month starting on March 3, 2011
ou
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Eu recomendo combinar isso com o sistema acima para obter mais flexibilidade. As tabelas para isso devem ser como:
E uma tabela chamada
events_meta
assim:repeat_week_im
representa a semana do mês atual, que pode estar entre 1 e 5 potencialmente.repeat_weekday
no dia da semana, 1-7.Agora, supondo que você esteja percorrendo os dias / semanas para criar uma exibição mensal em seu calendário, você pode compor uma consulta como esta:
Isso combinado com o método acima pode ser combinado para cobrir a maioria dos padrões de eventos repetidos / recorrentes. Se eu perdi alguma coisa, por favor deixe um comentário.
fonte
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
isto é/ EM2.meta_value
colocado incorretamente?86400
segundos em um dia, porque isso não leva em consideração o horário de verão. É mais apropriado calcular essas coisas dinamicamente em tempo real e, em vez disso, armazenarinterval = daily
einterval_count = 1
ouinterval = monthly
einterval_count = 1
.Embora a resposta atualmente aceita tenha sido uma grande ajuda para mim, eu queria compartilhar algumas modificações úteis que simplificam as consultas e também aumentam o desempenho.
Eventos de repetição "simples"
Para manipular eventos que se repetem em intervalos regulares, como:
ou
Você deve criar duas tabelas, uma chamada
events
assim:E uma tabela chamada
events_meta
assim:Por
repeat_start
ser uma data unix de data e hora sem hora (1369008000 corresponde a 20 de maio de 2013) erepeat_interval
uma quantidade em segundos entre os intervalos (604800 é de 7 dias).Ao percorrer todos os dias no calendário, você pode obter eventos repetidos usando esta consulta simples:
Basta substituir no timestamp unix (1299736800) por cada data em seu calendário.
Observe o uso do módulo (sinal de%). Esse símbolo é como uma divisão regular, mas retorna o '' restante '' em vez do quociente e, como tal, é 0 sempre que a data atual é um múltiplo exato do repeat_interval do repeat_start.
Comparação de desempenho
Isso é significativamente mais rápido que a resposta baseada em "meta_keys" sugerida anteriormente, que foi a seguinte:
Se você executar EXPLAIN esta consulta, notará que é necessário o uso de um buffer de junção:
A solução com 1 junção acima não requer esse buffer.
Padrões "complexos"
Você pode adicionar suporte para tipos mais complexos para suportar esses tipos de regras de repetição:
ou
Sua tabela de eventos pode ter exatamente a mesma aparência:
Em seguida, para adicionar suporte a essas regras complexas, adicione colunas da seguinte
events_meta
forma:Note que você só precisa especificar um
repeat_interval
ou um conjunto derepeat_year
,repeat_month
,repeat_day
,repeat_week
, erepeat_weekday
dados.Isso torna a seleção dos dois tipos simultaneamente muito simples. Basta percorrer todos os dias e preencher os valores corretos (1370563200 para 7 de junho de 2013 e depois o ano, mês, dia, número da semana e dia da semana da seguinte forma):
Isso retorna todos os eventos que se repetem na sexta-feira da 2ª semana, bem como todos os eventos que se repetem toda sexta-feira, portanto, retorna os IDs 1 e 2 do evento:
* Sidenote no SQL acima eu usei índices padrão do dia da semana do PHP Date , então "5" para sexta-feira
Espero que isso ajude os outros tanto quanto a resposta original me ajudou!
fonte
repeat_interval
coluna e representá-la nas colunas subseqüentes (ou sejarepeat_year
, etc.). Para a primeira linha, a situação de repetição toda segunda-feira após 20 de maio de 2013 pode ser representada colocando-se 1 norepeat_weekday
e um*
nas outras colunas.*
. Portanto, para "todo mês no dia 3", basta definirrepeat_day
3, o restante dosrepeat
campos como * (deixerepeat_interval
nulo) e defina o repeat_start como o código de tempo unix de 3 de março de 2011 para ser sua data de ancoragem.Aprimoramento: substitua o carimbo de data / hora pela data
Como um pequeno aprimoramento da resposta aceita que foi posteriormente refinada pelo ahoffner - é possível usar um formato de data em vez de carimbo de data e hora. As vantagens são:
para fazer isso, altere o banco
repeat_start
de dados para ser armazenado como tipo 'data' erepeat_interval
agora mantenha os dias em vez de segundos. ou seja, 7 por uma repetição de 7 dias.mude a linha sql:
para:
Tudo o resto permanece o mesmo. Simples!
fonte
Eu seguiria este guia: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
Além disso, certifique-se de usar o formato iCal para não reinventar a roda e lembre-se da Regra # 0: NÃO armazene instâncias de eventos recorrentes individuais como linhas no seu banco de dados!
fonte
attendedEvent
combaseInstanceId
einstanceStartDate
- Esse é, por exemplo, o evento base a partir do qual você criou a exibição do calendário de regras recorrentes e usou a data de início para especificar informações sobre essa instância específica. Essa entidade também pode tem algo parecido com oattendedListId
que leva a outra tabela deid
,attendedUserId
Para todos que estão interessados nisso, agora você pode simplesmente copiar e colar para começar em minutos. Eu segui o conselho nos comentários o melhor que pude. Deixe-me saber se estou faltando alguma coisa.
"VERSÃO COMPLEXA":
eventos
events_meta
Código SQL:
também disponível como exportação MySQL (para fácil acesso)
Exemplo de código PHP index.php:
Exemplo de código PHP connect.php:
Além disso, o código php está disponível aqui (para melhor legibilidade):
index.php
e
connect.php
Agora, configurar isso deve levar alguns minutos. Não horas. :)
fonte
Enquanto as soluções propostas funcionavam, eu estava tentando implementar com o Calendário completo e exigiria mais de 90 chamadas de banco de dados para cada visualização (como carrega o mês atual, o anterior e o próximo mês), das quais eu não estava muito empolgado.
Encontrei uma biblioteca de recursão https://github.com/tplaner/Quando você simplesmente armazena as regras no banco de dados e uma consulta para obter todas as regras relevantes.
Espero que isso ajude outra pessoa, pois passei muitas horas tentando encontrar uma boa solução.
Edit: Esta biblioteca é para PHP
fonte
When
Você tem que armazenar todas as datas recorrentes no banco de dados ou obter todos os eventos recorrentes e gerar datas no php no no banco de dados. Estou certo?When
para gerar todas as datas - que são preenchidas a partir das datas / regras armazenadas inicialmente.Por que não usar um mecanismo semelhante aos trabalhos do cron Apache? http://en.wikipedia.org/wiki/Cron
Para calendar \ scheduling, eu usaria valores ligeiramente diferentes para "bits" para acomodar eventos padrão de recorrência do calendário - em vez de [dia da semana (0 a 7), mês (1 a 12), dia do mês (1 a 31), hora (0 - 23), min (0 - 59)]
- Eu usaria algo como [Ano (repita a cada N anos), mês (1-12), dia do mês (1-31), semana do mês (1-5), dia da semana (0 - 7) ]
Espero que isto ajude.
fonte
Eu desenvolvi uma linguagem de programação esotérica apenas para este caso. A melhor parte disso é que ele é menos esquema e independente de plataforma. Você apenas precisa escrever um programa seletor, para sua programação, cuja sintaxe é restrita pelo conjunto de regras descritas aqui -
https://github.com/tusharmath/sheql/wiki/Rules
As regras são extensíveis e você pode adicionar qualquer tipo de personalização com base no tipo de lógica de repetição que deseja executar, sem se preocupar com migrações de esquema etc.
Essa é uma abordagem completamente diferente e pode ter algumas desvantagens.
fonte
Parece muito com eventos do MySQL que são armazenados nas tabelas do sistema. Você pode olhar para a estrutura e descobrir quais colunas não são necessárias:
fonte
O padrão RRULE foi criado exatamente para esse requisito, ou seja, salvando e entendendo as recorrências. A Microsoft e o Google os usam nos eventos da agenda. Por favor, leia este documento para obter mais detalhes. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
fonte
@Rogue Coder
Isso é ótimo!
Você pode simplesmente usar a operação modulo (MOD ou% no mysql) para simplificar seu código no final:
Ao invés de:
Faz:
Para levar isso adiante, pode-se incluir eventos que não se repetem para sempre.
Algo como "repeat_interval_1_end" para indicar a data do último "repeat_interval_1" pode ser adicionado. No entanto, isso torna a consulta mais complicada e eu realmente não consigo descobrir como fazer isso ...
Talvez alguém possa ajudar!
fonte
Os dois exemplos que você deu são muito simples; eles podem ser representados como um intervalo simples (o primeiro sendo quatro dias, o segundo sendo 14 dias). Como você modela isso dependerá inteiramente da complexidade de suas recorrências. Se o que você tem acima é realmente simples, armazene uma data de início e o número de dias no intervalo de repetição.
Se, no entanto, você precisar apoiar coisas como
Ou
Então esse é um padrão muito mais complexo.
fonte