sql >> Base de Datos >  >> RDS >> Mysql

Bases de datos:hacer un registro de acciones, ¿cómo manejar varias referencias?

Lo siguiente es cómo lo haría. Tengo algunos comentarios más en la parte inferior después de haber visto el esquema.

Iniciar sesión

LogID - ID de registro único

Hora - fecha/hora del evento

LogType - Cadena o ID

(comentario adicional, usaría una identificación aquí para que pueda usar una tabla de mensajes que se muestra a continuación, pero si quiere algo rápido y sucio, puede usar una cadena única para cada tiempo de registro (p. ej., "Juego iniciado", "Mensaje enviado"). , etc.)

LogActor

LogID - clave externa

LogActorType - Cadena o ID (como arriba, si es ID necesitará una tabla de búsqueda)

LogActorID:esta es una identificación única para la tabla para el tipo, por ejemplo, Usuario, Grupo, Juego

Secuencia:este es un orden de los actores.

Mensaje de registro

LogType - clave externa

Mensaje - cadena larga (varchar(max)?)

Idioma:cadena (5) para que pueda seleccionar diferentes idiomas, por ejemplo, "US-en"

Datos de ejemplo (usando sus 3 ejemplos)

Iniciar sesión

ID  Time   LogType 
1   1/1/10 1
2   1/1/10 2
3   1/1/10 3

Actor de registro

LogID LogActorType LogActorID Sequence
1     User         1          1
1     User         2          2
2     User         1          1
2     User         2          2
2     User         2          3
2     Game         1          4
3     User         3          1
3     Group        1          2

Mensaje de registro

LogType Message 
1       {0} Made a new friend {1}
2       {0}, {1}, {2} played a game ({3})
3       {0} joined a group ({1})

Usuario

ID Name
1  User A
2  User B
3  User C

Juego

ID Name
1  Name of game

Grupo

ID Name
1  Name of group

Estas son las cosas buenas de este diseño.

  • Es muy fácil de extender

  • Maneja problemas multilingües independientemente de los actores

  • Es autodocumentado, la tabla LogMessage explica exactamente lo que deben decir los datos que está almacenando.

Algunas cosas malas al respecto.

  • Tienes que hacer un procesamiento complicado para leer los mensajes.

  • No puede simplemente mirar la base de datos y ver qué sucedió.

En mi experiencia, las partes buenas de este tipo de diseño superan las partes malas. Lo que he hecho para permitirme hacer una mirada rápida y sucia al registro es hacer una vista (que no uso para el código de la aplicación) que puedo ver cuando necesito ver lo que está pasando en la parte posterior. fin.

Hazme saber si tienes preguntas.

Actualización:algunas consultas de ejemplo

Todos mis ejemplos están en sqlserver 2005+, avíseme si hay una versión diferente a la que desea que apunte.

Ver la tabla de LogActor (hay varias formas de hacer esto, la mejor depende de muchas cosas, incluida la distribución de datos, los casos de uso, etc.). Estas son dos:

a)

SELECT 
  LogId,
  COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
  Sequence
FROM LogActor A
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence

b)

SELECT 
  LogId,
  U.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
UNION ALL
SELECT 
  LogId,
  Ga.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
UNION ALL
SELECT 
  LogId,
  Go.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence

En general, creo que a) es mejor que b). Por ejemplo, si falta un actor, escriba a) lo incluirá (con un nombre nulo). Sin embargo, b) es más fácil de mantener (porque las declaraciones UNION ALL lo hacen más modular). Hay otras formas de hacerlo (por ejemplo, CTE, vistas, etc.). Me inclino a hacerlo como b) y, por lo que he visto, parece ser al menos una práctica estándar, si no la mejor práctica.

Entonces, los últimos 10 elementos en el registro se verían así:

SELECT 
  LogId,
  M.Message,
  COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
  Time,
  A.Sequence
FROM Log
LEFT JOIN LogActor A ON Log.LogID = A.LogID
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
LEFT JOIN LogMessage M ON Log.LogType = M.LogMessage
WHERE LogID IN (SELECT Top 10 LogID FROM Log ORDER BY Date DESC)
ORDER BY Date, LogID, A.Sequence

NB:como puede ver, es más fácil seleccionar todos los elementos de registro de una fecha que la última X, porque necesitamos una subconsulta (probablemente muy rápida) para esto.