Chcę przechowywać pojedynczy wiersz w tabeli konfiguracji dla mojej aplikacji. Chciałbym wymusić, aby ta tabela zawierała tylko jeden wiersz.
Jaki jest najprostszy sposób na wymuszenie ograniczenia jednego wiersza?
Chcę przechowywać pojedynczy wiersz w tabeli konfiguracji dla mojej aplikacji. Chciałbym wymusić, aby ta tabela zawierała tylko jeden wiersz.
Jaki jest najprostszy sposób na wymuszenie ograniczenia jednego wiersza?
Name
?
ar
komentarz s. Problem polega na tym, że jeśli przechowujesz tylko pary nazwa / wartość, wartość całkiem dobrze musi być ciągiem i nie masz możliwości wymuszenia walidacji w bazie danych. Gdy używasz jednorzędowej tabeli z oddzielnymi kolumnami dla każdego ustawienia (zgodnie z wymaganiami OP), możesz łatwo wymusić walidację dla każdego ustawienia konfiguracji za pomocą ograniczeń sprawdzających.
Odpowiedzi:
Upewnij się, że jedna z kolumn może zawierać tylko jedną wartość, a następnie ustaw ją jako klucz podstawowy (lub zastosuj ograniczenie niepowtarzalności).
CREATE TABLE T1(
Lock char(1) not null,
/* Other columns */,
constraint PK_T1 PRIMARY KEY (Lock),
constraint CK_T1_Locked CHECK (Lock='X')
)
Mam wiele takich tabel w różnych bazach danych, głównie do przechowywania konfiguracji. O wiele przyjemniej jest wiedzieć, że jeśli element konfiguracyjny powinien być intem, zawsze będziesz czytać tylko int z DB.
comp.databases.theory
grupy usenet (widocznej przez grupy Google), o której przyznaję, że ostatnio niewiele czytałem. Był bardziej zorientowany na teorię relacyjną niż na SQL - ale akurat wiedziałem, że dportas / sqlvogel również uczęszczał do tej samej grupy. TTM było nawiązaniem do Trzeciego Manifestu , który jest dobrą książką mówiącą (znowu) o teorii relacyjnej, a nie o SQL.
Zwykle stosuję podejście Damiena, które zawsze działało świetnie, ale dodam też jedną rzecz:
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')
)
Dodając „DEFAULT 'X'”, nigdy nie będziesz musiał zajmować się kolumną Lock i nie będziesz musiał pamiętać, która była wartością blokady podczas ładowania tabeli po raz pierwszy.
Lock char(1) not null CONSTRAINT DF_T1_Lock DEFAULT 'X'
Możesz przemyśleć tę strategię. W podobnych sytuacjach często uważałem za nieocenione pozostawienie starych rzędów konfiguracji w poszukiwaniu informacji historycznych.
Aby to zrobić, faktycznie masz dodatkową kolumnę creation_date_time
(data / godzina wstawienia lub aktualizacji) i wyzwalacz wstawiania lub wstawiania / aktualizacji, który wypełni ją poprawnie bieżącą datą / godziną.
Następnie, aby uzyskać aktualną konfigurację, użyj czegoś takiego:
select * from config_table order by creation_date_time desc fetch first row only
(w zależności od twojego smaku DBMS).
W ten sposób nadal możesz zachować historię do celów odzyskiwania (możesz wprowadzić procedury czyszczenia, jeśli tabela stanie się zbyt duża, ale jest to mało prawdopodobne) i nadal możesz pracować z najnowszą konfiguracją.
SELECT TOP 1 ... ORDER BY creation_date_time DESC
Możesz zaimplementować wyzwalacz INSTEAD OF Trigger, aby wymusić ten typ logiki biznesowej w bazie danych.
Wyzwalacz może zawierać logikę, aby sprawdzić, czy rekord już istnieje w tabeli, a jeśli tak, ROLLBACK wstawkę.
Teraz, cofając się, by spojrzeć na szerszą perspektywę, zastanawiam się, czy może istnieje alternatywny i bardziej odpowiedni sposób przechowywania tych informacji, na przykład w pliku konfiguracyjnym lub zmiennej środowiskowej?
Używam pola bitowego dla klucza podstawowego o nazwie IsActive. Więc mogą być maksymalnie 2 wiersze, a sql, aby uzyskać prawidłowy wiersz, to: wybierz * z Ustawień, gdzie IsActive = 1, jeśli tabela ma nazwę Ustawienia.
Oto rozwiązanie, które wymyśliłem dla tabeli typu blokady, która może zawierać tylko jeden wiersz, zawierający Y lub N (na przykład stan blokady aplikacji).
Utwórz tabelę z jedną kolumną. Położyłem ograniczenie sprawdzające na jednej kolumnie, aby można było w niej umieścić tylko Y lub N. (Lub 1 lub 0 lub cokolwiek)
Wstaw jeden wiersz w tabeli ze stanem „normalnym” (np. N oznacza niezablokowane)
Następnie utwórz wyzwalacz INSERT w tabeli, która ma tylko SIGNAL (DB2) lub RAISERROR (SQL Server) lub RAISE_APPLICATION_ERROR (Oracle). To sprawia, że kod aplikacji może aktualizować tabelę, ale każda operacja INSERT kończy się niepowodzeniem.
Przykład 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';
Pracuje dla mnie.
Stare pytanie, ale co powiesz na użycie IDENTITY (MAX, 1) małego typu kolumny?
CREATE TABLE [dbo].[Config](
[ID] [tinyint] IDENTITY(255,1) NOT NULL,
[Config1] [nvarchar](max) NOT NULL,
[Config2] [nvarchar](max) NOT NULL
IF NOT EXISTS ( select * from table )
BEGIN
///Your insert statement
END
Tutaj możemy również stworzyć niewidoczną wartość, która będzie taka sama po pierwszym wpisie do bazy danych Przykład: Tabela uczniów: Id: int firstname: char Tutaj w polu wejściowym musimy podać tę samą wartość dla kolumny id, która ograniczy jak po pierwszym wpisie innym niż zapis lock bla bla ze względu na ograniczenie klucza podstawowego, a zatem posiadanie tylko jednego wiersza na zawsze. Mam nadzieję że to pomoże!
(Name, Value)
z kluczem podstawowym w nazwie. Wtedy możesz miećselect Value from Table where Name = ?
pewność, że nie zostaną zwrócone żadne wiersze lub jeden wiersz.