Modify a row that is under a foreign key constraint - sqlite

I have a table with integer columns as below. The purpose of the bexParentID and bexParentTypeID columns is to be foreign-key constrained to other rows in the same table, i.e. (bexParentID,bexParentTypeID) has a composite FK constraint to (bexID,bexTypeID) in the same table.
This is the create script:
CREATE TABLE [main].[Boolean_Expressions](
[bexID] INTEGER PRIMARY KEY NOT NULL,
[bexTypeID] INTEGER NOT NULL,
[bexParentID] INTEGER NOT NULL,
[bexParentTypeID] INTEGER NOT NULL,
FOREIGN KEY([bexParentID], [bexParentTypeID]) REFERENCES [Boolean_Expressions]([bexID], [bexTypeID]),
UNIQUE([bexID], [bexTypeID]);
table design
Here is an example of data that might appear in this table.
data
How do I update the Type of a row (call it A) that has foreign-key constraints from rows B, C, D... on it? It is a violation to update the ParentType of the rows B, C, D..., and it is also a violation to update Type in A first.
I can only think of 'pointing' B, C, D.... to another row by changing their ParentID and ParentType to point to an altogether different row (call it X), then changing A's Type, then 'pointing' B, C, D... back to A.

Add ON UPDATE CASCADE to the FK constraint:
FOREIGN KEY([bexParentID], [bexParentTypeID]) REFERENCES [Boolean_Expressions]([bexID], [bexTypeID]) ON UPDATE CASCADE
Effect: it is sufficient to update the parent row; all dependent child rows will be updated to have the same value.

Two options that could be simpler.
a) Turn Foreign keys Off before the update and then On after the update. Using 'PRAGMA foreign_keys = off' and 'PRAGMA foreign_keys = on'
= false (off) or = true (on) or = 0 (off) or = 1 (on) (any value greater then 0 is on)
note cannot be effectively used (aka it's a NOP) inside a transaction.
e.g.
PRAGMA foreign_keys = off;
UPDATE ....;
PRAGMA foreign_keys = on;
or
b) Use deferred Foreign Keys, that is include:-
DEFERRABLE INITIALLY DEFERRED
In the Foreign Key definition(s).
e.g.
bexParentID INTEGER NOT NULL REFERENCES mytable1(bexID) DEFERRABLE INITIALLY DEFERRED
The Foreign Key conflict is checked when the transaction is committed. So the changes would need to be done inside a transaction. e.g.
BEGIN TRASNACTION;
UPDATE ....;
END TRANSACTION;

Related

MariaDB - Foreign key constraint incorrect?

I tried to re-engineer a database, that I use at work. The one at work is MS Access. At home, it's MariaDB. For convenience, I use MySQL Workbench.
When sending the complete SQL dump to the server, I get an error concerning some foreign key not being correctly formed. I guess, it is a minor mistake, but still I cannot find it.
My InnoDB status tells me this:
LATEST FOREIGN KEY ERROR
2018-10-03 00:18:29 409c7450 Error in foreign key constraint of table `mydb`.`IF`:
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblBelegPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tblBelege_tblECKassenschnittPositionen10`
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblECKassenschnittPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB:
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.6/en/innodb-foreign-key-constraints.html
for correct foreign key definition.
Create table '`mydb`.`IF`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near '
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblBelegPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tblBelege_tblECKassenschnittPositionen10`
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblECKassenschnittPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB'.
The really weird thing is that I do not have any table named "IF"...
Can anyone make heads or tails of this for me? That would be very much appreciated.
-- Table `mydb`.`tblBelegPositionen`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`tblBelegPositionen` ;
SHOW WARNINGS;
CREATE TABLE IF NOT EXISTS `mydb`.`tblBelegPositionen` (
`belegposid` INT NOT NULL AUTO_INCREMENT,
`belegposBetrag` DOUBLE NOT NULL,
`zahlartfID` INT NOT NULL,
`belegfID` INT NOT NULL,
PRIMARY KEY (`belegposid`))
ENGINE = InnoDB;
SHOW WARNINGS;
-- Table `mydb`.`tblECKassenschnittPositionen`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`tblECKassenschnittPositionen` ;
SHOW WARNINGS;
CREATE TABLE IF NOT EXISTS `mydb`.`tblECKassenschnittPositionen` (
`ecposid` INT NOT NULL AUTO_INCREMENT,
`belegfID` INT NOT NULL,
`ecposBetrag` DOUBLE NOT NULL,
`kassenschnittfID` INT NOT NULL,
PRIMARY KEY (`ecposid`))
ENGINE = InnoDB;
SHOW WARNINGS;
-- Table `mydb`.`tblBelege`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`tblBelege` ;
SHOW WARNINGS;
CREATE TABLE IF NOT EXISTS `mydb`.`tblBelege` (
`belegid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`belegKassierer` INT NOT NULL,
`belegDatum` DATETIME NOT NULL,
`kassefID` INT NOT NULL,
`belegSchicht` INT NULL,
`gvfID` INT NOT NULL,
`belegJahr` YEAR NULL,
`belegDruckErfolgt` TINYINT(1) NULL,
`belegDruckDatum` DATETIME NULL,
`belegPeriodenfremdeBuchung` TINYINT(1) NULL,
PRIMARY KEY (`belegid`, `gvfID`, `kassefID`),
CONSTRAINT `fk_tblBelege_tblBelegPositionen10`
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblBelegPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tblBelege_tblECKassenschnittPositionen10`
FOREIGN KEY (`belegid`)
REFERENCES `mydb`.`tblECKassenschnittPositionen` (`belegfID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SHOW WARNINGS;
Ok, so there are a couple of things to know here, as there were a couple of errors. You must check all the items that the error mentions, for correctness, to avoid trouble.
The cannot find an index in the referenced table portion of the error message means that the column/field specified in the REFERENCES clause must be indexed in the other table.
Then, the column type definition of the column specified in the FOREIGN KEY clause must match the column type of the column specified in the REFERENCES clause too, so even though the first item corrects part of the problem, there will still be an error related to another portion of the message: ...or column types in the table and the referenced table do not match.
So, to fix item 1, run these 2 queries:
ALTER TABLE `tblbelegpositionen` ADD INDEX(`belegfID`);
ALTER TABLE `tbleckassenschnittpositionen` ADD INDEX(`belegfID`);
Then to fix item 2, I had to change the first column of table tblBelege
from this:
`belegid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
to this:
`belegid` INT NOT NULL,
...so that they matched the same type as the belegfID column as defined in the other tables. After those two changes, I was able to successfully run your CREATE TABLE `tblBelege` statement.
So, to recap:
Run your create table statements for tblbelegpositionen and
tbleckassenschnittpositionen.
Then run the 2 ALTER statements shown above for item 1.
Modify the first column of table tblBelege to match the column types as defined to belegfID in the other tables for item 2.
Then run your modified CREATE TABLE statement (with the item 2 change applied) to create the tblBelege table.
I'm a little confused about the same FOREIGN KEY referencing 2 different tables, but if it works for you, then ok. (not saying that it cannot be done, I've never used a foreign key that way) Perhaps you meant the opposite, to have a foreign key in the other 2 tables (1 in each table) that refer to tblBelege instead? If so, then you could add unsigned to the type definition for belegfID and it would work, and would not need the change that I mentioned with item 2.
Oh, and after you run the ALTER statements, you can view the table structure by running:
SHOW CREATE TABLE `tblbelegpositionen`;
SHOW CREATE TABLE `tbleckassenschnittpositionen`;
...to get the KEY definition that was added to include with your CREATE TABLE statements. Since they both create the same key, you really only need to run one of those statements and then add the KEY definition to both table statements.

how to form composite unique key in dynamo db

I have a table in dynamo DB with the fields A, B, C, D and E.
The primary key is A(partition key) and B(sort key).
I want to have another unique constraint for C and D together as a composite unique key. In mysql I would do something like this
ALTER TABLE YourTable
add CONSTRAINT YourTable_unique UNIQUE (C, D);
I want to do something similar in dynamo DB so that when i create a new entry with an already matching composite unique key(C and D), it does not allow me to create that entry.
from documentation:
To write an item only if it doesn't already exist,
use PutItem with a conditional expression that uses the
attribute_not_exists function and the name of the table's
partition key
you cant add constraint on other keys then partition keys (you cant add constraint on global secondary key)
#Eyal Ch is right. I handled it at the application level, by doing a scan before saving like this :
DynamoDBScanExpression expr = new DynamoDBScanExpression();
expr.addFilterCondition("C",new Condition()
.withComparisonOperator(ComparisonOperator.EQ)
.withAttributeValueList(new AttributeValue().withS("value of C")));
expr.addFilterCondition("D",new Condition()
.withComparisonOperator(ComparisonOperator.EQ)
.withAttributeValueList(new AttributeValue().withS("value of D")));
List<TableClass> responseList = mapper.scan(TableClass.class, expr);
if (responseList.size() == 0){
........//save the record here
}

Can you use Nulls as part of a multi-column uniqueness check in SQLite?

Consider a simple self-referencing table in SQLite with the following fields
Create Table Test{
Id INTEGER PRIMARY KEY, <-- Alias for the RowId
Name TEXT NOT NULL CHECK(length(Name) > 0),
ParentId INTEGER REFERENCES Test(Id),
};
CREATE UNIQUE INDEX IX_UniqueNamePerLevel ON Test(ParentId, Name);
We're trying to set a uniqueness constraint on Name for all items which share the same ParentId. In other words, you can have two items with the name 'Joe' provided those items do not have the same ParentId.
The problem is that SQLite seems to treat nulls as distinct, meaning for any level except root items, the constraint works, but you can have fifteen 'Joe' entries all with a ParentId of 'null.'
Bonus points if you can show how to make that constraint trim leading and trailing whitespace on insert/update, and ignore case for the uniqueness constraint too.
SQLite treats NULLs in UNIQUE constraints as distinct for compatibility with other databases.
It is not possible to use a CHECK constraint for this because it would have to access other rows from the table, but subqueries are not allowed in CHECK.
You would have to use a trigger:
CREATE TRIGGER Test_ParentName_unique_insert_check
AFTER INSERT ON Test
FOR EACH ROW
WHEN NEW.ParentId IS NULL
BEGIN
SELECT RAISE(ABORT, 'root items must be unique, too')
FROM Test
WHERE ParentId IS NULL
AND Name = NEW.Name
AND Id <> NEW.Id;
END;

Abort due to constraint violation columns C1,C2,C3 are not unique

I have a composite primary key(C1+C2+C3)on a table.
Here is the DDL
CREATE TABLE "InputFiles" (
[PlantID] INTEGER,
[FileID] INTEGER,
[VesselDataCase] CHAR(9),
[Comments] CHAR(73),
Primary key([PlantID], [FileID]),
FOREIGN KEY(PlantId) REFERENCES Plant(PlantId) ON DELETE CASCADE);
CREATE TABLE [VesselData] (
[MaterialType] NVARCHAR(100) NOT NULL,
[Operating_Temperature] NUMERIC,
[IRTndt] numeric,
[VDID] integer,
[PlantId] integer,
[FileId] integer,
FOREIGN KEY([plantid], [fileid]) REFERENCES [inputfiles]([plantid], [fileid]) ON DELETE cascade,
CONSTRAINT [sqlite_autoindex_VesselData_1] PRIMARY KEY ([VDID], [PlantId], [FileId]));
When I try to insert a new row in VesselData Table
Suppose VDID = 1, Fileid = 2, Plantid = 3. So it looks for(1+2+3) combination.
Even though fields with these values dont exist in the Table, it gives me
Abort due to constraint violation
columns VDID, PlantId, FileId are not unique SQlite exception
But, it is inserting the field in the table. After inserting this field it gives me this exception. Either it shouldn't insert or abort due to invalid field values
Thank you
Sun

counting rows of sqlite INSERT SELECT

I have two sqlite tables, where one table has a foreign key of the other.
CREATE TABLE a (id INTEGER PRIMARY KEY NOT NULL, value TEXT UNIQUE NOT NULL);
CREATE TABLE b (id INTEGER PRIMARY KEY NOT NULL, a INTEGER REFERENCES a (id) NOT NULL, value TEXT NOT NULL);
I am doing an INSERT with a SELECT into b.
INSERT INTO b (a, value) SELECT ?value, a.id FROM a WHERE a.value == ?a;
How do I know weather a row was inserted into b or not? Doing a SELECT for the just inserted values and checking weather they exist, seems rather inefficient.
I hope the changes() function can help you.
The changes() function returns the number of database rows that were
changed or inserted or deleted by the most recently completed INSERT,
DELETE, or UPDATE statement, exclusive of statements in lower-level
triggers. The changes() SQL function is a wrapper around the
sqlite3_changes() C/C++ function and hence follows the same rules for
counting changes.
So changes() returns 1 if a row was inserted and 0 otherwise.

Resources