create virtual column in mariadb with case statement fails - mariadb

I am trying to create a table in MariaDB with a virtual column, defined by a case statement
This is what I have
create table Foto (
ID int AUTO_INCREMENT not null primary key,
LigPlaatsCode varchar(10) not null,
FotoTypeID int not null check (FotoType in (0, 1, 2, 3)),
Foto varchar(1000) not null,
FotoType varchar(50) as
case FotoTypeID
when 0 then 'Bidprent'
when 1 then 'Krantartikel'
when 2 then 'Persoon'
else 'Graf'
end, `
constraint FK_Foto_LigPlaats foreign key (LigPlaatsCode) references LigPlaats (LigPlaatsCode)
)
however it always gives me this error
#42000You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use
near 'case FotoTypeID
when 0 then 'Bidprent'
when 1 then 'Krantar' at line 7
When I google on how to create virtual column and case, the links I found seem to suggest I got it right, but obviously I dont. So I am missing something.
What is wrong with this create table statement ?
EDIT
my version is 10.3.21-MariaDB

Generated column requires parantehese around case expression:
create table Foto (
ID int AUTO_INCREMENT not null primary key,
LigPlaatsCode varchar(10) not null,
FotoTypeID int not null ,
Foto varchar(1000) not null,
FotoType varchar(50) as
(case FotoTypeID
when 0 then 'Bidprent'
when 1 then 'Krantartikel'
when 2 then 'Persoon'
else 'Graf'
end), -- brackets around
-- constraint as separate entry because it is referencing FotoType
constraint fototypecheck check (FotoType in (0, 1, 2, 3))
);
db<>fiddle demo
This line does not make sense as FotoType is text:
FotoTypeID int not null check (FotoType in (0, 1, 2, 3)),
-- probably it should be
FotoTypeID int not null check (FotoTypeID in (0, 1, 2, 3)),

Related

How to make something similar as an if statement in Sqlite?

This is my SQLite file:
CREATE TABLE IF NOT EXISTS COTXE ( /*Table to create the cars*/
matricula VARCHAR(7) NOT NULL PRIMARY KEY, /*CarPlate*/
marca INTEGER, /*Brand*/
color INTEGER /*Color*/
);
CREATE TABLE IF NOT EXISTS PLASA ( /*Table to crate all the sites of the parking*/
pos INTEGER NOT NULL PRIMARY KEY, /*Number of the parkingsite*/
superficie INTEGER, /*How many m² it has*/
ocupada BOOL /*If its empty or not (0 = empty)*/
);
CREATE TABLE IF NOT EXISTS APARCAR ( /*Table to park a car in a site of the parking*/
pos_plaça INTEGER, /*Number of the parking site*/
matricula VARCHAR(7), /*Carplate*/
data_in DEFAULT CURRENT_TIMESTAMP, /*Date when it enters the parking*/
data_out DEFAULT NULL, /*Date when it leaves the parking*/
PRIMARY KEY (matricula, data_in),
FOREIGN KEY (pos_plaça) REFERENCES PLASA(pos),
FOREIGN KEY (matricula) REFERENCES COTXE(matricula)
);
/*Inserts to add cars and parking sites*/
INSERT INTO COTXE VALUES ('9882JPX', 0, 0);
INSERT INTO COTXE VALUES ('1111DDD', 4, 9);
INSERT INTO COTXE VALUES ('2222SSS', 8, 8);
INSERT INTO COTXE VALUES ('3333FFF', 3, 5);
INSERT INTO PLASA (superficie, ocupada) VALUES (50, 0);
INSERT INTO PLASA (superficie, ocupada) VALUES (34, 0);
INSERT INTO PLASA (superficie, ocupada) VALUES (24, 0);
I've got a little problem and its when i try to add, for example the first car two times in the same parking site without leaving in any of those it adds again the same car in the same parking site that should be impossible, i drop here an example:
sqlite> INSERT INTO APARCAR (pos_plaça, matricula) VALUES (1, '9882JPX');
sqlite> UPDATE PLASA SET ocupada = 1 WHERE pos = 1;
sqlite> INSERT INTO APARCAR (pos_plaça, matricula) VALUES (1, '9882JPX');
sqlite> SELECT * FROM APARCAR;
pos_plaça matricula data_in data_out
---------- ---------- ------------------- ----------
1 9882JPX 2022-03-17 17:41:24
1 9882JPX 2022-03-17 17:41:26
So i'm asking you guys if any of you know how to condition the INSERT INTO and before adding the car in that parking site, check if its full.
Sorry for my bad english and explanations.

No limitation on SQL column data type

I have SQLite database (created in SQLiteStudio).
The DDL is this:
CREATE TABLE player (
player_id INTEGER PRIMARY KEY ASC AUTOINCREMENT
UNIQUE
NOT NULL,
first_nickname STRING (10) NOT NULL,
health INTEGER (100) NOT NULL,
gold INTEGER (99) NOT NULL,
silver INTEGER (99) NOT NULL,
bronze INTEGER (99) NOT NULL,
gerium INTEGER (99) NOT NULL
);
Expected: I shouldn't be able to insert integers higher than 100 into health column.
What happens: For some reason, I can insert numbers higher than 100
Why was I able to...
INSERT INTO player (first_nickname, health, gold, silver, bronze, gerium) VALUES ('Foo', 101, 0, 0, 15, 0)
...if my health's column is set to INTEGER with max value of 100?
Why am I able to insert 101 when I should only be able to enter 100?
When you define a column as INTEGER(100) or use any other value inside the parentheses, this does not create any constraint for the values of the column.
In fact SQLite totally ignores it.
SQLite does not even check the data type of the column, so you can insert not numeric strings in a column defined as INTEGER without any error.
The same applies to STRING(10) as there is no STRING data type in SQLite, but you should use TEXT.
All this is explained clearly in Datatypes In SQLite.
If you want to create such constraints you must explicitly define CHECK constraints, something like:
CREATE TABLE player (
player_id INTEGER PRIMARY KEY ASC AUTOINCREMENT NOT NULL,
first_nickname TEXT NOT NULL CHECK(LENGTH(first_nickname) <= 10),
health INTEGER NOT NULL CHECK(health BETWEEN 0 AND 100),
gold INTEGER NOT NULL CHECK(gold BETWEEN 0 AND 99),
silver INTEGER NOT NULL CHECK(silver BETWEEN 0 AND 99),
bronze INTEGER NOT NULL CHECK(bronze BETWEEN 0 AND 99),
gerium INTEGER NOT NULL CHECK(gerium BETWEEN 0 AND 99)
);
See a simplified demo.

SQLite composite key for a table between two tables

I am trying to Connect Three tables. Two of them have Primary Keys which the Third is supposed to link to. I need this inbetween as it is linked to a fourth (but this Works fine). The code I have written is as follows:
CREATE TABLE CUSTOMERS(
CUSTOMER_ID INT(10) NOT NULL,
SURNAME CHAR(50) NOT NULL,
NAME CHAR(50) NOT NULL,
PRIMARY KEY (CUSTOMER_ID)
);
CREATE TABLE WORKSHOP(
WORKSHOP_ID INT(10) NOT NULL,
NAME CHAR(100) NOT NULL,
CHAIN_NAME CHAR(100),
CHAIN_ID INT(10),
CONTRACT_WORKSHOP CHAR(5) NOT NULL,
PRIMARY KEY (WORKSHOP_ID, CHAIN_ID)
);
CREATE TABLE CAR_DAMAGE(
DAMAGE_ID INT(10) NOT NULL,
CUSTOMER_ID INT(10) NOT NULL,
DATE INT(20) NOT NULL,
PLACE CHAR(128) NOT NULL,
WORKSHOP_ID INT(10) NOT NULL,
PRIMARY KEY (DAMAGE_ID, CUSTOMER_ID, WORKSHOP_ID, DATE, PLACE),
FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMERS (CUSTOMER_ID),
FOREIGN KEY (WORKSHOP_ID) REFERENCES WORKSHOP (WORKSHOP_ID)
);
INSERT INTO CUSTOMERS VALUES (1, "OLSEN", "TROND");
INSERT INTO CUSTOMERS VALUES (2, "JOHNSEN", "FELIX");
INSERT INTO CUSTOMERS VALUES (3, "SVINDAL", "AKSEL");
INSERT INTO CUSTOMERS VALUES (4, "BJORGEN", "MARIT");
INSERT INTO CUSTOMERS VALUES (5, "SVENDSON", "LISA");
INSERT INTO WORKSHOP VALUES (1, "BERTEL", "MOLLER", 1, "YES");
INSERT INTO WORKSHOP VALUES (2, "OLOF", "OLOF AUTO", 3, "NO");
INSERT INTO WORKSHOP VALUES (3, "J-AUTO", "MOLLER", 1, "YES");
INSERT INTO WORKSHOP VALUES (4, "SPEED", "BIRGER N. HAUG", 2, "YES");
INSERT INTO WORKSHOP VALUES (5, "RELAX AUTO", "MOLLER", 1, "YES");
INSERT INTO CAR_DAMAGE VALUES (1, 1, 10102008, "HELLERUD", 1);
INSERT INTO CAR_DAMAGE VALUES (2, 2, 14032015, "JAR", 2);
INSERT INTO CAR_DAMAGE VALUES (3, 3, 24052016, "LOMMEDALEN", 3);
INSERT INTO CAR_DAMAGE VALUES (4, 4, 31102017, "FLAKTVEIT", 4);
INSERT INTO CAR_DAMAGE VALUES (5, 5, 08062016, "STOCKHOLM", 5);
However, the problem occur as I get the error "foriegn key mismatch - CAR_DAMAGE referencing WORKSHOP.
I am using SQLite as I am forced to use it, given by my University.
Table WORKSHOP has a composite primary key (WORKSHOP_ID, CHAIN_ID). Any foreign key referencing that table must be a composite foreign key, consisting of the same two fields. Hence, you would need to add CHAIN_ID to table WORKSHOP and change your foreign key declaration to something like:
FOREIGN KEY (WORKSHOP_ID, CHAIN_ID) REFERENCES WORKSHOP (WORKSHOP_ID, CHAIN_ID)
[More generally, your primary keys seem, based on the information given, more complex than they need to be: why not just have WORKSHOP_ID as PK of WORKSHOP and DAMAGE_ID as PK of CAR_DAMAGE? But maybe you have good reasons.]
Thank you. This Method worked. Hence, when I proceeded, a New problem occured. The table CAR_DAMAGE is linked to a fourth table (Called DAMAGE_INFORMATION), With the code:
CREATE TABLE DAMAGE_INFORMATION(
DAMAGE_ID INT(10) NOT NULL,
DAMAGE_TYPE CHAR(100) NOT NULL,
DAMAGE_SIZE CHAR(50) NOT NULL,
SPEND INT(10) NOT NULL,
FOREIGN KEY (DAMAGE_ID) REFERENCES CAR_DAMAGE (DAMAGE_ID)
);
And I receive the same error as earlier, i.e. Foreign key mismatch "DAMAGE_INFORMATION" referencing "CAR_DAMAGE".
Is it not allowed to make a combination of 3 tables to 1, With different primary keys? The primary key of CAR_DAMAGE is:
PRIMARY KEY (DAMAGE_KEY, CUSTOMER_ID, WORKSHOP_ID)

Single insertion of data on one date in SQL Server?

ALTER PROCEDURE [dbo].[K_FS_InsertMrpDetails]
#date datetime,
#feedtype varchar(50),
#rateperkg float,
#rateper50kg float,
#updatedby varchar(50)
AS
BEGIN
INSERT INTO K_FS_FeedMrpDetails([date], feedtype, rateperkg, rateper50kg, updatedby, updatedon)
VALUES(#date, #feedtype, #rateperkg, #rateper50kg, #updatedby, getdate())
SELECT '1' AS status
END
With this query we insert 9 rows at a time but what I want is in one same date do not insert again different details. How can I please help me.
Add a unique constraint on the column [date]. That will prevent you from adding more than one row with the same [date] value.
Update:
To allow 9 rows for each date you can add a computed column D that removes the time part and you need to add a column that will hold the values 1 to 9 R. Use a check constraint on R to only allow 1-9. Finally you create a unique constraint on (R, D).
Sample table definition:
create table T
(
ID int identity primary key,
DT datetime not null,
R tinyint check (R in (1,2,3,4,5,6,7,8,9)) not null,
D as dateadd(day, datediff(day, 0, DT), 0),
constraint ux_RD unique (R,D)
)
Try with this:
insert into T(DT, R) values(getdate(), 1)
insert into T(DT, R) values(getdate(), 2)
insert into T(DT, R) values(getdate(), 1)
First and second insert works fine, the third raises a unique constraint exception.

SQLite Insert and Replace with condition

I can not figure out how to query a SQLite.
needed:
1) Replace the record (the primary key), if the condition (comparison of new and old fields entries)
2) Insert an entry if no such entry exists in the database on the primary key.
Importantly, it has to work very fast!
I can not come up with an effective inquiry.
Edit.
MyInsertRequest - the desired expression.
Script:
CREATE TABLE testtable (a INT PRIMARY KEY, b INT, c INT)
INSERT INTO testtable VALUES (1, 2, 3)
select * from testtable
1|2|3
-- Adds an entry, because the primary key is not
++ MyInsertRequest VALUES (2, 2, 3) {if c>4 then replace}
select * from testtable
1|2|3
2|2|3
-- Adds
++ MyInsertRequest VALUES (3, 8, 3) {if c>4 then replace}
select * from testtable
1|2|3
2|2|3
3|8|3
-- Does nothing, because such a record (from primary key field 'a')
-- is in the database and none c>4
++ MyInsertRequest VALUES (1, 2, 3) {if c>4 then replace}
select * from testtable
1|2|3
2|2|3
3|8|3
-- Does nothing
++ MyInsertRequest VALUES (3, 34, 3) {if c>4 then replace}
select * from testtable
1|2|3
2|2|3
3|8|3
-- replace, because such a record (from primary key field 'a')
-- is in the database and c>2
++ MyInsertRequest VALUES (3, 34, 1) {if c>2 then replace}
select * from testtable
1|2|3
2|2|3
3|34|1
Isn't INSERT OR REPLACE what you need ? e.g. :
INSERT OR REPLACE INTO table (cola, colb) values (valuea, valueb)
When a UNIQUE constraint violation occurs, the REPLACE algorithm
deletes pre-existing rows that are causing the constraint violation
prior to inserting or updating the current row and the command
continues executing normally.
You have to put the condition in a unique constraint on the table. It will automatically create an index to make the check efficient.
e.g.
-- here the condition is on columnA, columnB
CREATE TABLE sometable (columnPK INT PRIMARY KEY,
columnA INT,
columnB INT,
columnC INT,
CONSTRAINT constname UNIQUE (columnA, columnB)
)
INSERT INTO sometable VALUES (1, 1, 1, 0);
INSERT INTO sometable VALUES (2, 1, 2, 0);
select * from sometable
1|1|1|0
2|1|2|0
-- insert a line with a new PK, but with existing values for (columnA, columnB)
-- the line with PK 2 will be replaced
INSERT OR REPLACE INTO sometable VALUES (12, 1, 2, 6)
select * from sometable
1|1|1|0
12|1|2|6
Assuming your requirements are:
Insert a new row when a doesn't exists;
Replacing row when a exist and existing c greater then new c;
Do nothing when a exist and existing c lesser or equal then new c;
INSERT OR REPLACE fits first two requirements.
For last requirement, the only way I know to make an INSERT ineffective is supplying a empty rowset.
A SQLite command like following whould make the job:
INSERT OR REPLACE INTO sometable SELECT newdata.* FROM
(SELECT 3 AS a, 2 AS b, 1 AS c) AS newdata
LEFT JOIN sometable ON newdata.a=sometable.a
WHERE newdata.c<sometable.c OR sometable.a IS NULL;
New data (3,2,1 in this example) is LEFT JOINen with current table data.
Then WHERE will "de-select" the row when new c is not less then existing c, keeping it when row is new, ie, sometable.* IS NULL.
I tried the others answers because I was also suffering from a solution to this problem.
This should work, however I am unsure about the performance implications. I believe that you may need the first column to be unique as a primary key else it will simply insert a new record each time.
INSERT OR REPLACE INTO sometable
SELECT columnA, columnB, columnC FROM (
SELECT columnA, columnB, columnC, 1 AS tmp FROM sometable
WHERE sometable.columnA = 1 AND
sometable.columnB > 9
UNION
SELECT 1 AS columnA, 1 As columnB, 404 as columnC, 0 AS tmp)
ORDER BY tmp DESC
LIMIT 1
In this case one dummy query is executed and union-ed onto a second query which would have a performance impact depending on how it is written and how the table is indexed. The next performance problem has potential where the results are ordered and limited. However, I expect that the second query should only return one record and therefore it should not be too much of a performance hit.
You can also omit the ORDER BY tmp LIMIT 1 and it works with my version of sqlite, but it may impact performance since it can end up updating the record twice (writing the original value then the new value if applicable).
The other problem is that you end up with a write to the table even if the condition states that it should not be updated.

Resources