T-SQL to SQLite conversion - sqlite

I have the following T-SQL statement for creating a table which I have modified to work with SQLite
CREATE TABLE prerequisite_lesson(
next_lesson_id INT NOT NULL,
prereq_lesson_id INT NOT NULL,
CHECK(prereq_lesson_id) NOT (lesson_id),
CONSTRAINT pk_prereq PRIMARY KEY (lesson_id, prereq_lesson_id),
FOREIGN KEY(next_lesson_id) REFERENCES lessons(lesson_id),
FOREIGN KEY(prereq_lesson_id) REFERENCES lessons(lesson_id));
I'm getting 4 errors when I try to create the table as follows:
Unrecognized data type. (near "(" at position 111)
A comma or a closing bracket was expected. (near "prereq_lesson_id" at position 112)
Unexpected beginning of statement. (near "prereq_lesson_id" at position 112)
Unrecognized statement type. (near "NOT" at position 130)
Can anyone offer help with the errors? Thanks in advance.

Had to create lessons first.
create table lessons(
lesson_id int primary key not null
);
Then there is something with constraint check syntax. Please see an example here. Also for primary key pair probably need next_lesson_id instead of lesson_id.
CREATE TABLE prerequisite_lesson(
next_lesson_id INT NOT NULL,
prereq_lesson_id INT NOT NULL CHECK(NOT(next_lesson_id)),
CONSTRAINT pk_prereq PRIMARY KEY (next_lesson_id, prereq_lesson_id),
FOREIGN KEY(next_lesson_id) REFERENCES lessons(lesson_id),
FOREIGN KEY(prereq_lesson_id) REFERENCES lessons(lesson_id));
Full schema creation fiddle here.

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.

sqlite integer primary key not null constraint failed

According to the SQLite documentation / FAQ a column declared INTEGER PRIMARY KEY will automatically get a value of +1 the highest of the column if omitted.
Using SQLite version 3.22.0 2018-01-22 18:45:57
Creating a table as follows:
CREATE TABLE test (
demo_id INTEGER PRIMARY KEY NOT NULL,
ttt VARCHAR(40) NOT NULL,
basic VARCHAR(25) NOT NULL,
name VARCHAR(255) NOT NULL,
UNIQUE(ttt, basic) ON CONFLICT ROLLBACK
) WITHOUT ROWID;
Then inserting like this:
INSERT INTO test (ttt, basic, name) VALUES ('foo', 'bar', 'This is
a test');
gives:
Error: NOT NULL constraint failed: test.demo_id
sqlite>
When it is expected to create a record with a demo_id value of 1. Even if the table already contains values, it'll fail inserting the row without explicitly specifying the id with the same error.
What am I doing wrong?
The documentation says that you get autoincrementing values for the rowid. But you specified WITHOUT ROWID.

Foreign key mismatch SQLite

I searched all the documentation about this and I can't seem to understans what's the problem, maybe an experienced could help me.
So I'm creating a table called LOCALIZACAO:
CREATE TABLE LOCALIZACAO(
id INTEGER PRIMARY KEY AUTOINCREMENT,
rua TEXT NOT NULL,
codigoPostal TEXT NOT NULL,
UNIQUE (codigoPostal));
And this other table that references LOCALIZACAO, called SOCIOLOCALIZACAO:
CREATE TABLE SOCIOLOCALIZACAO(
idS INTEGER REFERENCES SOCIO(idS),
idL INTEGER NOT NULL REFERENCES LOCALIZACAO(idL),
CONSTRAINT pk_SOCIOLOCALIZACAO PRIMARY KEY (idS),
CONSTRAINT fk_SOCIOLOCALIZACAO FOREIGN KEY (idL) REFERENCES LOCALIZACAO(id) ON DELETE CASCADE ON UPDATE CASCADE);
Altough I'm inserting elements on the LOCALIZACAO table, when I'm inserting on the SOCIOLOCALIZACAO table:
INSERT INTO SOCIOLOCALIZACAO VALUES (1,1);
I'm given an error
foreign key mismatch "SOCIOLOCALIZACAO" referencing "LOCALIZACAO"
I'm sure there is the element 1 in SOCIO and in LOCALIZACAO
Here is the SOCIO table:
CREATE TABLE SOCIO(
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome TEXT NOT NULL,
anoDeNascimento INTEGER NOT NULL,
numeroDeSocio INTEGER NOT NULL CHECK (numeroDeSocio > 0),
nif INTEGER NOT NULL CHECK (nif > 99999999 AND nif < 1000000000),
anoDeVinculacao INTEGER NOT NULL CHECK (anoDeNascimento < anoDeVinculacao),
UNIQUE (nome, nif),
UNIQUE (numeroDeSocio));
Any help is appreciated!
Thank you!
Your foreign key references the fields idS and idL in table LOCALIZACAO. There are no such fields, there's only an id field there.
I guess you're only seeing this when inserting records because SQLite is not very pedantic. Other databases wouldn't have let you create such a foreign key.

ORA-00907: missing right parenthesis when creating tables

I am trying to create 3 tables but I am getting this error:
CREATE TABLE dj_abonent
(
dj_klientID INT NOT NULL PRIMARY KEY,
emer_klienti varchar2(10),
mbiemer_klienti VARCHAR2(10),
sasia_cel INT
);
CREATE TABLE dj_phones
(
phone_number varchar2(12),
activated number(1) default 0,
activation_date date default null,
CONSTRAINT dj_phone_number_check
CHECK (substr(phone_number,1,5) in( '35566','35567','35568','35569') ),
CONSTRAINT dj_activated_check
CHECK (activated in(1,0) )
dj_KlientID int FOREIGN KEY REFERENCES dj_Abonenti(dj_KlientID)
);
CREATE TABLE dj_telef
(
start_time date,
end_time date,
abonent_1 varchar2(10),
abonent_2 varchar2(10)
);
Error at Command Line : 26 Column : 17
Error report -
SQL Error: ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
The line number is from your SQL Developer script window, which isn't entirely helpful as it doesn't seem to align with the issue. There may be other things too but you're missing a comma after your check constraint (just like a previous question). But you should put the constraints at the end of the command:
CREATE TABLE dj_phones
(
phone_number varchar2(12),
activated number(1) default 0,
activation_date date default null,
dj_KlientID int FOREIGN KEY REFERENCES dj_Abonenti(dj_KlientID)
CONSTRAINT dj_phone_number_check
CHECK (substr(phone_number,1,5) in( '35566','35567','35568','35569') ),
CONSTRAINT dj_activated_check
CHECK (activated in(1,0) )
);
You might find it easier to debug these issues if you ran one statement at a time, either with the run statement command (control-enter), or by highlighting the text one one command and using run script (F5).

INSERT IF NOT EXISTS ELSE UPDATE?

I've found a few "would be" solutions for the classic "How do I insert a new record or update one if it already exists" but I cannot get any of them to work in SQLite.
I have a table defined as follows:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
What I want to do is add a record with a unique Name. If the Name already exists, I want to modify the fields.
Can somebody tell me how to do this please?
Have a look at http://sqlite.org/lang_conflict.html.
You want something like:
insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);
Note that any field not in the insert list will be set to NULL if the row already exists in the table. This is why there's a subselect for the ID column: In the replacement case the statement would set it to NULL and then a fresh ID would be allocated.
This approach can also be used if you want to leave particular field values alone if the row in the replacement case but set the field to NULL in the insert case.
For example, assuming you want to leave Seen alone:
insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
(select ID from Book where Name = "SearchName"),
"SearchName",
5,
6,
(select Seen from Book where Name = "SearchName"));
You should use the INSERT OR IGNORE command followed by an UPDATE command:
In the following example name is a primary key:
INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'
The first command will insert the record. If the record exists, it will ignore the error caused by the conflict with an existing primary key.
The second command will update the record (which now definitely exists)
You need to set a constraint on the table to trigger a "conflict" which you then resolve by doing a replace:
CREATE TABLE data (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);
Then you can issue:
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);
The "SELECT * FROM data" will give you:
2|2|2|3.0
3|1|2|5.0
Note that the data.id is "3" and not "1" because REPLACE does a DELETE and INSERT, not an UPDATE. This also means that you must ensure that you define all necessary columns or you will get unexpected NULL values.
INSERT OR REPLACE will replace the other fields to default value.
sqlite> CREATE TABLE Book (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
);
sqlite> INSERT INTO Book VALUES (1001, 'C++', 10, 10, 0);
sqlite> SELECT * FROM Book;
1001|C++|10|10|0
sqlite> INSERT OR REPLACE INTO Book(ID, Name) VALUES(1001, 'SQLite');
sqlite> SELECT * FROM Book;
1001|SQLite|||
If you want to preserve the other field
Method 1
sqlite> SELECT * FROM Book;
1001|C++|10|10|0
sqlite> INSERT OR IGNORE INTO Book(ID) VALUES(1001);
sqlite> UPDATE Book SET Name='SQLite' WHERE ID=1001;
sqlite> SELECT * FROM Book;
1001|SQLite|10|10|0
Method 2
Using UPSERT (syntax was added to SQLite with version 3.24.0 (2018-06-04))
INSERT INTO Book (ID, Name)
VALUES (1001, 'SQLite')
ON CONFLICT (ID) DO
UPDATE SET Name=excluded.Name;
The excluded. prefix equal to the value in VALUES ('SQLite').
Firstly update it. If affected row count = 0 then insert it. Its the easiest and suitable for all RDBMS.
Upsert is what you want. UPSERT syntax was added to SQLite with version 3.24.0 (2018-06-04).
CREATE TABLE phonebook2(
name TEXT PRIMARY KEY,
phonenumber TEXT,
validDate DATE
);
INSERT INTO phonebook2(name,phonenumber,validDate)
VALUES('Alice','704-555-1212','2018-05-08')
ON CONFLICT(name) DO UPDATE SET
phonenumber=excluded.phonenumber,
validDate=excluded.validDate
WHERE excluded.validDate>phonebook2.validDate;
Be warned that at this point the actual word "UPSERT" is not part of the upsert syntax.
The correct syntax is
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
and if you are doing INSERT INTO SELECT ... your select needs at least WHERE true to solve parser ambiguity about the token ON with the join syntax.
Be warned that INSERT OR REPLACE... will delete the record before inserting a new one if it has to replace, which could be bad if you have foreign key cascades or other delete triggers.
If you have no primary key, You can insert if not exist, then do an update. The table must contain at least one entry before using this.
INSERT INTO Test
(id, name)
SELECT
101 as id,
'Bob' as name
FROM Test
WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;
Update Test SET id='101' WHERE name='Bob';
I believe you want UPSERT.
"INSERT OR REPLACE" without the additional trickery in that answer will reset any fields you don't specify to NULL or other default value. (This behavior of INSERT OR REPLACE is unlike UPDATE; it's exactly like INSERT, because it actually is INSERT; however if what you wanted is UPDATE-if-exists you probably want the UPDATE semantics and will be unpleasantly surprised by the actual result.)
The trickery from the suggested UPSERT implementation is basically to use INSERT OR REPLACE, but specify all fields, using embedded SELECT clauses to retrieve the current value for fields you don't want to change.
I think it's worth pointing out that there can be some unexpected behaviour here if you don't thoroughly understand how PRIMARY KEY and UNIQUE interact.
As an example, if you want to insert a record only if the NAME field isn't currently taken, and if it is, you want a constraint exception to fire to tell you, then INSERT OR REPLACE will not throw and exception and instead will resolve the UNIQUE constraint itself by replacing the conflicting record (the existing record with the same NAME). Gaspard's demonstrates this really well in his answer above.
If you want a constraint exception to fire, you have to use an INSERT statement, and rely on a separate UPDATE command to update the record once you know the name isn't taken.

Resources