2010-10-19 11 views
51

Quiero almacenar una sola fila en una tabla de configuración para mi aplicación. Me gustaría hacer cumplir que esta tabla puede contener solo una fila.Servidor SQL: ¿cómo restringir una tabla para que contenga una sola fila?

¿Cuál es la forma más simple de aplicar la restricción de fila única?

+0

¿Por qué no utilizar una tabla con columnas '(Nombre, Valor)' con una clave principal en Nombre. Entonces puede 'seleccionar Valor de la Tabla donde Nombre =?' Con certeza de que no se devolverán filas o una fila. –

+1

No estoy seguro de que sql sea la mejor solución aquí. Tal vez un simple archivo xml sea más apropiado para la configuración. Yo solía pensar que la configuración! = Data y sql estaban hechos para datos. –

+2

@ar - He visto que sale mal cuando espera leer, digamos, un entero, y obtiene un valor mal formateado en la columna de valor. –

Respuesta

67

Asegúrese de que una de las columnas solo contenga un valor y luego conviértala en la clave principal (o aplique una restricción de exclusividad).

CREATE TABLE T1(
    Lock char(1) not null, 
    /* Other columns */, 
    constraint PK_T1 PRIMARY KEY (Lock), 
    constraint CK_T1_Locked CHECK (Lock='X') 
) 

Tengo varias de estas tablas en varias bases de datos, principalmente para almacenar config. Es mucho mejor saber que, si el elemento de configuración debe ser un int, solo leerá un int del DB.

+1

+1. Este es el enfoque que Celko usa para una tabla de constantes auxiliares en "SQL for Smarties" –

+0

Esto es casi tan simple como se puede esperar. Gracias. – Martin

+0

+1: solución interesante. No había visto esto antes, así que gracias por compartir. Siempre el camino, fácil cuando sabes cómo ... –

4

Puede implementar un INSTEAD OF Trigger para hacer cumplir este tipo de lógica empresarial dentro de la base de datos.

El disparador puede contener lógica para verificar si ya existe un registro en la tabla y, de ser así, ROLLBACK el inserto.

Ahora, dando un paso atrás para ver una imagen más grande, me pregunto si tal vez hay una forma alternativa y más adecuada para almacenar esta información, tal vez en un archivo de configuración o variable de entorno, por ejemplo.

+0

+1 - Puedo ver cómo funcionaría el gatillo, y tal vez recurriré a ese enfoque, pero me gusta la restricción simple de Damien. Hay una discusión interesante sobre qué tipo de datos de configuración pertenece en el archivo de configuración y qué pertenece al DB. En este caso, creo que el DB es el lugar correcto. Sin duda voy a vivir para lamentar esto ... :-) – Martin

0
IF NOT EXISTS (select * from table) 
BEGIN 
    ///Your insert statement 
END 
1

Puede escribir un activador en la acción de inserción en la tabla. Cada vez que alguien intente insertar una nueva fila en la tabla, elimine la lógica de eliminar la última fila en el código de activación de inserción.

11

Es posible que desee replantearse esta estrategia. En situaciones similares, a menudo me pareció invaluable dejar las viejas filas de configuración para información histórica.

Para hacer eso, en realidad tiene una columna adicional creation_date_time (fecha/hora de inserción o actualización) y un disparador de inserción o inserción/actualización que se rellenará correctamente con la fecha/hora actual.

Luego, con el fin de obtener su configuración actual, utilice algo como:

select * from config_table order by creation_date_time desc fetch first row only 

(dependiendo de su sabor DBMS).

De esta forma, aún puede mantener el historial para fines de recuperación (puede establecer procedimientos de limpieza si la tabla es demasiado grande pero esto es poco probable) y aún puede trabajar con la última configuración.

+0

+1: Escucho lo que dices, pero prefiero registrar el historial de cambios en tablas de auditoría separadas. – Martin

+0

+1: para compartir la interesante idea de implementar una pista de auditoría. –

+0

Agradable. Simplemente 'SELECCIONAR TOP 1 ... ORDER BY creation_date_time DESC' – Baodad

37

que suelo utilizar el enfoque de Damien, que siempre ha funcionado muy bien para mí, pero también añadir una cosa:

CREATE TABLE T1(
    Lock char(1) not null DEFAULT 'X', 
    /* Other columns */, 
    constraint PK_T1 PRIMARY KEY (Lock), 
    constraint CK_T1_Locked CHECK (Lock='X') 
) 

Agregar el "DEFAULT 'X'", nunca tendrá que lidiar con el bloqueo columna, y no tendrá que recordar cuál era el valor de bloqueo al cargar la tabla por primera vez.

+3

+1 - buen consejo, gracias. – Martin

+0

La restricción predeterminada también debe nombrarse o de lo contrario obtendrá un nombre confuso autogenerado. 'Bloquear char (1) no nulo CONSTRAINT DF_T1_Lock DEFAULT 'X'' –

0

Aquí también podemos hacer un valor invisible que va a ser el mismo después de la primera entrada en el database.Example: Tabla Estudiante: Id: int Nombre: char Aquí, en el cuadro de entrada, tenemos que especificar el mismo valor para la columna id que se restringirá como después de la primera entrada que no sea la de bloqueo bla bla debido a la restricción de clave primaria teniendo así solo una fila para siempre. Espero que esto ayude!

2

Utilizo un campo de bit para la clave principal con el nombre IsActive. Así que puede haber 2 filas como máximo y y el sql para obtener la fila válida es: select * from Settings donde IsActive = 1 si la tabla se llama Settings.

2

Aquí hay una solución que se me ocurrió para una tabla de tipo de bloqueo que puede contener solo una fila, manteniendo una Y o N (un estado de bloqueo de la aplicación, por ejemplo).

Crea la tabla con una columna. Puse una restricción de verificación en la columna para que solo se pueda poner una Y o N en ella. (O 1 o 0, o lo que sea)

Insertar una fila en la tabla, con el estado "normal" (por ejemplo, N significa no bloqueado)

A continuación, crear un desencadenador de inserción en la mesa que sólo tiene una señal de (DB2) o RAISERROR (SQL Server) o RAISE_APPLICATION_ERROR (Oracle). Esto hace que el código de la aplicación pueda actualizar la tabla, pero cualquier INSERT falla.

ejemplo de DB2:

create table PRICE_LIST_LOCK 
(
    LOCKED_YN  char(1) not null 
     constraint PRICE_LIST_LOCK_YN_CK check (LOCKED_YN in ('Y', 'N')) 
); 
--- do this insert when creating the table 
insert into PRICE_LIST_LOCK 
values ('N'); 

--- once there is one row in the table, create this trigger 
CREATE TRIGGER ONLY_ONE_ROW_IN_PRICE_LIST_LOCK 
    NO CASCADE 
    BEFORE INSERT ON PRICE_LIST_LOCK 
    FOR EACH ROW 
    SIGNAL SQLSTATE '81000' -- arbitrary user-defined value 
    SET MESSAGE_TEXT='Only one row is allowed in this table'; 

funciona para mí.

0

Pregunta anterior, pero ¿qué tal el uso de la IDENTIDAD (MAX, 1) de un tipo de columna pequeña?

CREATE TABLE [dbo].[Config](
[ID] [tinyint] IDENTITY(255,1) NOT NULL, 
[Config1] [nvarchar](max) NOT NULL, 
[Config2] [nvarchar](max) NOT NULL 
Cuestiones relacionadas