2010-08-16 20 views
9

Decir que tengo dos tablas, user y comment. Tienen definiciones de las tablas que se ven así:MySQL con Soft-Supresión, clave única y restricciones de clave externa

CREATE TABLE `user` (
    `id`  INTEGER NOT NULL AUTO_INCREMENT, 
    `username` VARCHAR(255) NOT NULL, 
    `deleted` TINYINT(1) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY (`username`) 
) ENGINE=InnoDB;
CREATE TABLE `comment` (
    `id`  INTEGER NOT NULL AUTO_INCREMENT, 
    `user_id` INTEGER NOT NULL, 
    `comment` TEXT, 
    `deleted` TINYINT(1) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_comment_user_id` FOREIGN KEY (`user_id`) 
    REFERENCES `user` (`id`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE 
) ENGINE=InnoDB;

Esto es grande para hacer cumplir la integridad de datos y todo eso, pero yo quiero ser capaz de "eliminar" un usuario y mantener todos sus comentarios (para referencia del motivo).

Para este fin, he agregado deleted para que pueda SET deleted = 1 en un registro. Al enumerar todo con deleted = 0 de forma predeterminada, puedo ocultar todos los registros eliminados hasta que los necesite.

Hasta ahora todo bien.

El problema viene cuando:

  • un usuario se inscribe con un nombre de usuario (por ejemplo, "Sam"),
  • Me suave borro ese usuario (por razones no relacionadas), y
  • Alguien más viene para registrarse como Sam, y de repente hemos violado la restricción ÚNICA en user.

que desea que los usuarios puedan editar sus propios nombres de usuario, por lo que no debe hacer username la clave principal, y todavía va a tener el mismo problema al borrar usuarios.

¿Alguna idea?

Editar para aclaración: Agregado siguiendo las respuestas y los comentarios de RedFilter abajo.

me preocupa el caso de que los usuarios "borrados" y los comentarios no son visibles para el público, pero son visibles sólo los administradores, o se mantienen con el propósito de calcular las estadísticas.

Esta pregunta es un experimento mental, con las tablas de usuario y comentario simplemente ser ejemplos. Aún así, username no fue el mejor para usar; RedFilter hace puntos válidos sobre la identidad del usuario, particularmente cuando los registros se presentan en un contexto público.

En cuanto a "¿Por qué no se nombre de usuario de la clave principal?": Esto es sólo un ejemplo, pero si aplico a un problema real que voy a necesitar para trabajar dentro de las limitaciones de un sistema existente que asume la existencia de una clave primaria sustituta.

Respuesta

22

Añadir restricción única en campos (nombre de usuario, borra) Cambiar el tipo de campo para el 'borrado' a INTEGER.

Durante la operación de borrado (se puede hacer en el gatillo, o en parte del código en el que necesita realmente eliminar el usuario) copia el valor del campo id al campo de borrado.

Este enfoque le permitirá:

  • mantener nombres exclusivos para los usuarios activos (suprimido = 0)
  • permiten eliminar usuarios con mismo nombre de usuario varias veces

Campo 'borrado' no puede tener solo 2 valores porque la siguiente situación no funcionará:

  1. creas el usuario 'Sam'
  2. usuario Sam se elimina
  3. Se crea una nueva contraseña Nombre de usuario witn 'Sam'
  4. Intenta eliminar el usuario con nombre de usuario 'Sam' - falle. Ya tiene el registro userName = 'Sam' y eliminado = '1'
+5

Cambiar el tipo de campo de 'deleted' a' timestamp' le permitiría agregar más filas eliminadas allí. si desea registros existentes (no eliminados), busque 'null' en este campo. –

+1

@TahaPaksu que perdería el valor de la clave única Si ha permitido nulos en eliminada. –

+0

@eric_s este enfoque tiene que ser diseñado como "Todo menos 1 será tratada como 'no se eliminan'". –

3

Hemos de tener el índice único o contraint en username. No desea que los nuevos usuarios puedan usar el nombre eliminado, ya que no solo puede haber una confusión general sobre la identidad, pero si aún muestra las publicaciones anteriores del usuario eliminado, se entenderá que las publicará por error. el nuevo usuario con el mismo nombre.

Cuando un nuevo usuario se registra, lo haría normalmente comprobar para ver si el nombre está en uso antes de permitir el registro para completar, por lo que no debe haber ningún conflicto aquí.

.

+1

@RedFilter, No es una solución finalizada: no podrá marcar dos 'Sam' como eliminados. Piensa mejor copiar Id al campo eliminado durante la operación de eliminación. Esto permite que solo una persona permanezca activa y tiene varios usuarios eliminados con el mismo nombre (mediante el uso de constaint unique (name, deleted)). –

+1

@Michael: No estoy de acuerdo con que dos usuarios separados puedan usar el mismo nombre de usuario. – RedFilter

+1

@Michael: Primera reacción, "Eso es un truco". Segunda reacción, "Wow, eso es realmente muy inteligente". Es de suponer que significa para establecer la restricción a 'UNIQUE KEY (nombre de usuario, borrado)'. –

Cuestiones relacionadas