sqlite constraint base another table - sqlite

I have 2 tables CarParking and ParkingArea. On ParkingArea I need to save the MaxPricePerDay, and on CarParking I have to save the cost. I try to write constraint that the cost is under or equal to MaxPricePerDay base on the AID columnn.
How can I do that?
CREATE TABLE "CarParking" (
"StartTime" TIMESTAMP NOT NULL,
"EndTime" TIMESTAMP NOT NULL,
"Cost" INTEGER NOT NULL,
"CID" INTEGER NOT NULL,
"AID" INTEGER NOT NULL,
FOREIGN KEY("CID") REFERENCES "Car"("CID")
ON DELETE CASCADE,
FOREIGN KEY("AID") REFERENCES "ParkingArea"("AID")
ON DELETE SET NULL,
CONSTRAINT time_car CHECK(StartTime<=EndTime),
PRIMARY KEY("StartTime","CID")
);
CREATE TABLE "ParkingArea" (
"MaxPricePerDay" INTEGER NOT NULL,
"PricePerHour" INTEGER NOT NULL,
"Name" TEXT NOT NULL,
"AID" INTEGER UNIQUE NOT NULL,
"Neighborhood" INTEGER NOT NULL,
PRIMARY KEY("AID"),
FOREIGN KEY ("Neighborhood") REFERENCES "Neighborhood" ("NID")
ON DELETE CASCADE
);

Since CHECK constraints can't have subqueries, one way is using a trigger instead.
CREATE TRIGGER check_max_price BEFORE INSERT ON CarParking
BEGIN
SELECT raise(ABORT, 'Exceeded MaxPricePerDay')
FROM ParkingArea
WHERE aid = new.aid AND new.Cost > MaxPricePerDay;
END;
is a starting point; you'll have to tweak the calculation to see if the cost is too much as appropriate.
If your cost can be updated after a row is inserted, you'll want a similar trigger for UPDATE.

Related

How to make Transaction work as expected in DB Browser for SQLite?

I am testing a set of migration code on existing DB.
I have try to execute multiple SQLite statements within a transaction, in DB Browser for SQLite.
BEGIN TRANSACTION;
CREATE TABLE `plain_note_new` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `label` TEXT, `title` TEXT, `body` TEXT, `type` INTEGER NOT NULL, `color_index` INTEGER NOT NULL, `custom_color` INTEGER NOT NULL, `locked` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `checked` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `trashed` INTEGER NOT NULL, `sticky` INTEGER NOT NULL, `sticky_icon` INTEGER NOT NULL, `order` INTEGER NOT NULL, `searched_string` TEXT, `reminder_type` INTEGER NOT NULL, `reminder_timestamp` INTEGER NOT NULL, `reminder_repeat` INTEGER NOT NULL, `reminder_end_timestamp` INTEGER NOT NULL, `reminder_active_timestamp` INTEGER NOT NULL, `reminder_last_timestamp` INTEGER NOT NULL, `reminder_repeat_frequency` INTEGER NOT NULL, `reminder_day_of_week_bitwise` INTEGER NOT NULL, `created_timestamp` INTEGER NOT NULL, `modified_timestamp` INTEGER NOT NULL, `trashed_timestamp` INTEGER NOT NULL, `synced_timestamp` INTEGER NOT NULL, `uuid` TEXT NOT NULL);
INSERT INTO `plain_note_new` SELECT `id`, `label`, `title`, `body`, `type`, `color_index`, `custom_color`, `locked`, `pinned`, `checked`, `archived`, `trashed`, `sticky`, `sticky_icon`, `order`, `searched_string`, `reminder_type`, `reminder_timestamp`, `reminder_repeat`, `reminder_end_timestamp`, `reminder_active_timestamp`, `reminder_last_timestamp`, `reminder_repeat_frequency`, `reminder_day_of_week_bitwise`, `created_timestamp`, `modified_timestamp`, `trashed_timestamp`, `synced_timestamp`, `uuid` FROM `plain_note`;
DROP INDEX `index_plain_note_archived`;
DROP INDEX `index_plain_note_label`;
DROP INDEX `index_plain_note_sticky`;
DROP INDEX `index_plain_note_trashed`;
DROP INDEX `index_plain_note_uuid`;
DROP TABLE `plain_note`;
BAD COMMAND;
ALTER TABLE `plain_note_new` RENAME TO `plain_note`;
CREATE INDEX `index_plain_note_archived` ON `plain_note` (`archived`);
CREATE INDEX `index_plain_note_label` ON `plain_note` (`label`);
CREATE INDEX `index_plain_note_sticky` ON `plain_note` (`sticky`);
CREATE INDEX `index_plain_note_trashed` ON `plain_note` (`trashed`);
CREATE UNIQUE INDEX `index_plain_note_uuid` ON `plain_note` (`uuid`);
CREATE INDEX `index_plain_note_uuid_synced_timestamp` ON `plain_note` (`uuid`, `synced_timestamp`);
COMMIT;
I expect due to BAD COMMAND, the transaction will not be committed. Hence, both indices and table will not be dropped.
However, when I click on the Play button
The tables and indices are still being dropped.
Even I start all over again, and tried by removing COMMIT from the UI, the outcome is still not desired (plain_note table is removed, and multiple indices are removed)
I expect since we do not end the transaction, actual table and indices removal should not happen. May I know, why is it so?
DB Browser for sqlite manages transactions as per this doc. Observe that even if a COMMIT; is issued, the Write Changes and Revert Changes buttons are still active. I expect that DB4S discards transaction commands (begin, commit, rollback) to maintain the integrity of the Write and Revert Changes buttons.

how to insert multiple foreign key in DB Browser for SQLite (GUI)

I am using SQLite and DB Browser for SQLite. I know that if you want to insert a foreign key using the GUI, you just have to scroll to the right and double click to insert the foreign key to the corresponding field. The problem is when you want to use a multiple foreign key. How or where should i put the multiple foreign key constrain using the GUI ?
my actual sql is (returns an exception 'foreign key mismatch - "diseases" referencing "beehives"...'):
CREATE TABLE "diseases" (
"id" INTEGER NOT NULL,
"id_beehive" INTEGER NOT NULL,
"id_apiary" INTEGER NOT NULL,
"disease" TEXT NOT NULL,
"treatment" TEXT NOT NULL,
"start_treat_date" DATE NOT NULL,
"end_treat_date" DATE,
PRIMARY KEY("id"),
FOREIGN KEY("id_beehive") REFERENCES "beehives"("number") ON UPDATE CASCADE,
FOREIGN KEY("id_apiary") REFERENCES "beehives"("id_apiary") ON UPDATE CASCADE
);
what i want to do using the gui is:
CREATE TABLE "diseases" (
"id" INTEGER NOT NULL,
"id_beehive" INTEGER NOT NULL,
"id_apiary" INTEGER NOT NULL,
"disease" TEXT NOT NULL,
"treatment" TEXT NOT NULL,
"start_treat_date" DATE NOT NULL,
"end_treat_date" DATE,
PRIMARY KEY("id"),
FOREIGN KEY("id_beehive","id_apiary") REFERENCES "beehives"("number","id_apiary") ON UPDATE CASCADE
);
beehives sql:
CREATE TABLE "beehives" (
"number" INTEGER NOT NULL,
"id_apiary" INTEGER NOT NULL DEFAULT -2,
"date" DATE,
"type" TEXT,
"favorite" BOOLEAN DEFAULT 'false',
PRIMARY KEY("number","id_apiary"),
FOREIGN KEY("id_apiary") REFERENCES "apiaries"("id") ON DELETE SET NULL
);
After researching, it is not possible for the moment.
Everytime you modify the structure of the table, what DB Browser for SQLite do on the background is renaming the table, creating a new table with the updated structure, move the data to this new table and delete the old table. So in the GUI it looks like its only updating.
Unfortunatly, to create a composite foreign key or modify a simple FK to a composite FK , you can only do it manualy from the SQL window.
example :
FOREIGN KEY("id_beehive","id_apiary") REFERENCES "beehives"("number","id_apiary") ON
UPDATE CASCADE

How to prevent recursive hierarchies?

It would be helpful if the following two tables had a specific constraint:
-- Table: privilege_group
CREATE TABLE privilege_group (
privilege_group_id integer NOT NULL CONSTRAINT privilege_group_pk PRIMARY KEY AUTOINCREMENT,
name text NOT NULL,
CONSTRAINT privilege_group_name UNIQUE (name)
);
-- Table: privilege_relationship
CREATE TABLE privilege_relationship (
privilege_relationship_id integer NOT NULL CONSTRAINT privilege_relationship_pk PRIMARY KEY AUTOINCREMENT,
parent_id integer NOT NULL,
child_id integer NOT NULL,
CONSTRAINT privilege_relationship_parent_child UNIQUE (parent_id, child_id),
CONSTRAINT privilege_relationship_parent_id FOREIGN KEY (parent_id)
REFERENCES privilege_group (privilege_group_id),
CONSTRAINT privilege_relationship_child_id FOREIGN KEY (child_id)
REFERENCES privilege_group (privilege_group_id),
CONSTRAINT privilege_relationship_check CHECK (parent_id != child_id)
);
Each parent can have multiple children, and each child can have multiple parents. Processing relationships can be done outside of the database, but is there a way within the database to prevent recursive relationships?
My research shows that it is possible to use CREATE TRIGGER and to use a RAISE function to prevent something from completing, but the possibility of internal depth-first or breadth-first searches in SQLite3 is unknown to me.

Recursive foreign key 'on delete cascade'

CREATE TABLE IF NOT EXISTS type (
tid INTEGER NOT NULL,
uuid VARCHAR NOT NULL,
name VARCHAR NOT NULL,
CONSTRAINT PK PRIMARY KEY (tid),
CONSTRAINT UNQ_0 UNIQUE (uuid),
CONSTRAINT UNQ_1 UNIQUE (name)
);
CREATE INDEX IDX_type_0 ON type (tid,uuid,name);
CREATE TABLE IF NOT EXISTS object (
oid VARCHAR NOT NULL,
timestamp VARCHAR NOT NULL,
tid INTEGER NOT NULL,
CONSTRAINT FK_tid FOREIGN KEY (tid) REFERENCES type(tid) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT UNQ_0 UNIQUE (oid)
);
CREATE INDEX IDX_object_0 ON object (oid,timestamp,tid);
CREATE TABLE IF NOT EXISTS object_user_owner (
uid INTEGER NOT NULL,
oid VARCHAR NOT NULL,
CONSTRAINT FK_uid FOREIGN KEY (uid) REFERENCES user(uid) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT FK_oid FOREIGN KEY (oid) REFERENCES object(oid) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT UNQ_0 UNIQUE (oid,uid)
);
CREATE INDEX IDX_object_user_owner_0 ON object_user_owner (uid,oid);
CREATE TABLE IF NOT EXISTS user (
uid INTEGER NOT NULL,
uuid VARCHAR NOT NULL,
name VARCHAR NOT NULL,
password VARCHAR NOT NULL,
salt VARCHAR NOT NULL,
timestamp VARCHAR NOT NULL,
lastaccess VARCHAR NOT NULL,
CONSTRAINT PK PRIMARY KEY (uid),
CONSTRAINT UNQ_0 UNIQUE (uuid),
CONSTRAINT UNQ_1 UNIQUE (name)
);
CREATE INDEX IDX_user_0 ON user (uid,uuid,name);
The above three sqlite3 tables contain foreign keys. The problem is the deletion of a key in the upper table type. When I try do delete I get 'FOREIGN KEY constraint failed' Error. Deleting a from the lowest table object_user_owner before deleting a type works. I think sqlite does not check any recursive cascade constraints. Does anyone have experienced this too or is anything wrong with my design?

Drop Unique Key and generate new unique key

I have created one table in oracle data base my table script is
CREATE TABLE wsc_widget_bundle (
id VARCHAR (50),
widgetBundle BLOB NULL,
devicesoftwareclass VARCHAR(30) NOT NULL,
widgetProfileId VARCHAR (50) NOT NULL,
bundleHash BLOB NULL,
widgetLocale VARCHAR (6) NOT NULL ,
status INT,
primary key(id),
unique(widgetProfileId, devicesoftwareclass,status),
foreign key(widgetProfileId) references wsc_widget_profile(id)
);
When i create ddl for that is looks like
create table "DEV1"."WSC_WIDGET_BUNDLE"(
"ID" VARCHAR2(50) not null,
"WIDGETBUNDLE" BLOB,
"DEVICESOFTWARECLASS" VARCHAR2(30) not null,
"WIDGETPROFILEID" VARCHAR2(50) not null,
"BUNDLEHASH" BLOB,
"WIDGETLOCALE" VARCHAR2(6) not null,
"STATUS" NUMBER,
constraint "SYS_C00323290" primary key ("ID")
);
alter table "DEV1"."WSC_WIDGET_BUNDLE"
add constraint "SYS_C00323292"
foreign key ("WIDGETPROFILEID")
references "MTP440_DEV1"."WSC_WIDGET_PROFILE"("ID");
create unique index "MTP440_DEV1"."SYS_C00323290" on "MTP440_DEV1"."WSC_WIDGET_BUNDLE"("ID");
create unique index "MTP440_DEV1"."SYS_C00323291" on "MTP440_DEV1"."WSC_WIDGET_BUNDLE"("WIDGETPROFILEID","DEVICESOFTWARECLASS","STATUS");
create index "MTP440_DEV1"."TEST" on "MTP440_DEV1"."WSC_WIDGET_BUNDLE"("DEVICESOFTWARECLASS","STATUS","WIDGETLOCALE","WIDGETPROFILEID");
Now i want to write alter script to alter unique key constrain of my table but as at creation of table I didn't mention the name of my unique key name it is given by system like SYS_C00323291
So how can I write alter script to drop that unique key whose name is not known to me and generation new one
You can find the name of the constraint by querying the user_constraints and user_cons_columns views.
Alter table x
drop constraint pk;
Alter table x
add constraint New_constraint_name PRIMARY KEY (colname);

Resources