Constraint not working as desired for my INSERT? - sql

I am creating a Table named "Cliente" with some constraints on it as it follows:
CREATE TABLE public."Cliente" (
"K_CODCLIENTE" numeric(5) NOT NULL,
"N_NOMBRE1" varchar(15) NOT NULL,
"N_NOMBRE2" varchar(15) NOT NULL,
"N_APELLIDO1" varchar(15) NOT NULL,
"N_APELLIDO2" varchar(15),
"N_DIRECCION" varchar(50) NOT NULL,
"Q_TELEFONO" numeric(10) NOT NULL,
"K_CODREF" numeric(5),
"I_TIPOID" varchar(2) NOT NULL,
"Q_IDENTIFICACION" varchar(10) NOT NULL,
CONSTRAINT "PK_Cliente" PRIMARY KEY ("K_CODCLIENTE"),
CONSTRAINT "UQ_ID_TIPOID_CLIENTE" UNIQUE ("I_TIPOID","Q_IDENTIFICACION"),
CONSTRAINT "CK_CODCLIENTE" CHECK ("K_CODCLIENTE" >= 100),
CONSTRAINT "CK_Q_IDENTIFICACION" CHECK ("Q_IDENTIFICACION" IN ('CC', 'PA', 'CE', 'NI', 'OT'))
);
When I try to insert some values on it:
INSERT INTO "Cliente"
VALUES ('101','Juan','Felipe','Ortiz','Rojas','AK 15 no. 28-05','3101125507',null,'CC','51111111');
I get the following error (in PostgreSQL 14, on Fedora):
[23514] ERROR: new row for relation "Cliente" violates check constraint "CK_Q_IDENTIFICACION"
Detail: Failing row contains (101, Juan, Felipe, Ortiz, Rojas, AK 15 no. 28-05, 3101125507, null, CC, 51111111).
I am trying to restrict the "Q_IDENTIFICACION" column so it can only be filled with 'CC', 'PA', 'CE, 'NI' or 'OT'.
Maybe I'm doing something wrong when declaring the constraint "CK_Q_IDENTIFICACION"?

Seems like you messed up the mapping of values and are trying to insert '51111111' to "Q_IDENTIFICACION".
Consider this more revealing variant with a formatted list of target columns:
INSERT INTO "Cliente"
("K_CODCLIENTE", "N_NOMBRE1", "N_NOMBRE2", "N_APELLIDO1", "N_APELLIDO2", "N_DIRECCION" , "Q_TELEFONO", "K_CODREF", "I_TIPOID", "Q_IDENTIFICACION")
VALUES ('101' , 'Juan' ,'Felipe' , 'Ortiz' , 'Rojas' , 'AK 15 no. 28-05', '3101125507', NULL , 'CC' , '51111111'); -- !
Maybe you want to switch the last two column names in the table definition - and (not) adapt the VALUES list in the INSERT accordingly? (varchar(2) vs. varchar(10) seems switched as well.)
For persisted code, it's generally advisable to spell out target columns in an INSERT command in any case.
Asides:
Reconsider all these pesky double-quoted upper case identifiers. See:
Are PostgreSQL column names case-sensitive?
Consider plain type text instead of varchar(n) with strikingly tight character limits. See:
Any downsides of using data type "text" for storing strings?

Related

How to prevent a input of certain letters using Oracle

The code is the category of the video, it is represented by one upper case character, excluding I, O,
Q, V, Y and Z, followed by a numeric character.
So far, I took a guess and got this. Any suggestions on how to fix it?
create table channelTable (
channelID number NOT NULL,
ChannelName varchar(100) NOT NULL,
ChannelDate date NOT NULL,
UserName varchar(100) NOT NULL UNIQUE,
TopicCode varchar(4) NOT NULL);
CONSTRAINT channelID_pk PRIMARY KEY (channelID)
CONSTRAINT c_topicCode LIKE '[A-Za-z][0-9] NOT (I,O,Q,N,Y,Z)
);
Some comments:
NOT NULL is not needed for PRIMARY KEY columns.
In Oracle, use VARCHAR2().
Then, I would suggests regular expressions. If the value is supposed to be exactly two characters, then declare it as such:
create table channelTable (
channelID number,
ChannelName varchar(100) NOT NULL,
ChannelDate date NOT NULL,
UserName varchar2(100) NOT NULL UNIQUE,
TopicCode char(2) NOT NULL;
CONSTRAINT channelID_pk PRIMARY KEY (channelID)
CONSTRAINT check (REGEXP_LIKE(c_topicCode, '^[A-HJ-NPR-UYZ][0-9]$')
);
Or perhaps more simply:
CONSTRAINT REGEXP_LIKE(c_topicCode, '^[A-Z][0-9]$') AND NOT REGEXP_LIKE(c_topicCode, '^[IOQNYZ]'))
All that said, I would rather see a table of TopicCodes that is populated with the correct values. Then you can just use a foreign key relationship to define the appropriate codes.
Use the regular expression ^[A-HJ-MPR-X]\d$ to match an upper-case character excluding I,O,Q,N,Y,Z followed by a digit:
CREATE TABLE channels (
id number CONSTRAINT channel__id__pk PRIMARY KEY,
Name varchar(100) CONSTRAINT channel__name__nn NOT NULL,
DateTime date CONSTRAINT channel__date__nn NOT NULL,
UserName varchar(100) CONSTRAINT channel__username__NN NOT NULL
CONSTRAINT channel__username__U UNIQUE,
TopicCode varchar(4),
CONSTRAINT channel__topiccode__chk CHECK ( REGEXP_LIKE( topiccode, '^[A-HJ-MPR-X]\d$' ) )
);
db<>fiddle
Also, you don't need to call the table channeltable just call it channels and you don't need to prefix the column names with the table name and you can name all the constraints (rather than relying on system generated constraint names which makes it much harder to track down issues when you are debugging).
Consider the following check constrait:
create table channelTable (
...
topicCode varchar(4) not null
check(
substr(c_topicCode, 1, 1) not in ('I', 'O', 'Q', 'V', 'Y', 'Z')
and regexp_like(topicCode, '^[A-Z]\d')
),
...
);
The first condition ensures that the code does not start with one of the forbidden characters, the second valides that it stats with an upper alphabetic character, followed by a number.
To avoid using two conditions, an alternative would be to list all allowed characters in the first position:
check(regexp_like(topicCode, '^[ABCDEFGHJKLMNPRSTUVWX]\d'))
This works in Oracle, and in very recent versions of MySQL.

How to fix an SQL design

I'm doing the study of a medical software. This software asks the patients questions about their symptoms and from them it can determine the possible pathologies. My study involves comparing the symptoms and pathologies found by the software with those from the hospital.
In order to make my work easier, I decided to enter the data in a database made with javadb on netbeans 8.2.
But it seems like that I did something wrong since my statement doesn't work.
I thank you in advance anybody who would take the time to help me.
SQL design:
Create table Patients(
nip varchar(32) primary key,
sexe varchar(8) not null,
age int not null,
dateArrivee timestamp not null,
constraint ck_sexe check(sexe='Male' or sexe='Female'),
constraint ck_age check (age>=0)
);
Create table Symptoms(
symptomID int primary key generated always as identity (start with 1,
increment by 1),
nip varchar(32) not null,
symptom varchar(64),
origin varchar(16) not null,
foreign key (nip) references Patients(nip),
constraint ck_origin check (origin='SOFTWARE' or origin='HOSPITAL')
);
Create table Pathologies(
pathologyID int primary key generated always as identity (start with 1,
increment by 1),
nip varchar(32) not null,
pathology varchar(64),
origin varchar(16) not null,
foreign key (nip) references Patients(nip),
constraint ck_origin check (origin='SOFTWARE' or origin='HOSPITAL')
);
Values entered:
Insert into Patients values ('001','Male', 25, '2019-05-27 14:00:00');
Insert into Patients values ('002', 'Female', 30, '2019-05-26 15:00:00');
Insert into Symptoms values (, '001', 'Headache', 'SOFTWARE');
Insert into Pathologies values (,'001', 'Fever', 'SOFTWARE');
Insert into Symptoms values (,'001', 'Stomache', 'HOSTPITAL');
Insert into Pathologies values (, '001', 'Gastro-enteritis', 'HOSPITAL');
Insert into Symptoms values(,'002', 'Headache', 'SOFTWARE');
Insert into Pathologies values (,'002', 'Unknow', 'SOFTWARE');
SQL statement:
Select *
from (Patients inner join
Symptoms
on Patients.nip = Symptoms.nip
) inner join
Pathologies
on Symptoms.nip = Pathologies.nip
where Symptoms.origin = 'MEDVIR' and
Pathologies.origin = 'MEDVIR';
So sorry I forgot to put the errors I'm getting.
SQL design:
First I have an error concerning the auto_incrementation, even thought this was the good method. It says that the syntax is incorrect near the 'generated'.
Values entered:
Here I have an error concerning the a wrong syntax near the coma (',').
SQL statement:
Lastly I have an error saying that the object 'Patients' is unavaible.
If I am not wrong, you are trying to fetch entries where 'Origin' = 'MEDVIR'
Although, none of your insert statements have Origin as 'MEDVIR'
Please check below,
Select *
from (Patients inner join
Symptoms
on Patients.nip = Symptoms.nip
) inner join
Pathologies
on Symptoms.nip = Pathologies.nip
where Symptoms.origin IN ('SOFTWARE', 'HOSPITAL') and
Pathologies.origin IN ('SOFTWARE', 'HOSPITAL');
Also, some of your INSERT statement has an extra comma before the values, which would cause a syntax error.

PostgreSQL, how can i populate this table which has two foreign keys as it's fields

I have a problem when trying to populate a table using a script using the psql terminal window and the -f option (this executes the script).
I can populate the piste and lift tables fine no problems at all, but i have another table which contains foreign key's to these tables. I can create the table fine, but i cannot add anything to the table, i simply have no idea how to do this.
My tables:
piste {piste_name {PK}, grade, length, fall, open}
lift {lift_name {PK}, lift_type, summit, rise, length, operating}
lift_location {piste_name*{PK}, lift_name*{PK}}
My script:
CREATE TABLE piste (
piste_name varchar(30) PRIMARY KEY NOT NULL,
grade varchar(10) NOT NULL,
length decimal NOT NULL,
fall smallint NOT NULL,
open boolean NOT NULL
);
CREATE TABLE lift (
lift_name varchar(20) PRIMARY KEY NOT NULL,
lift_type varchar(10) NOT NULL,
summit smallint NOT NULL,
rise smallint NOT NULL,
length smallint NOT NULL,
operating boolean NOT NULL
);
CREATE TABLE lift_location (
piste_name varchar(30) REFERENCES piste(piste_name),
lift_name varchar(20) REFERENCES lift(lift_name),
PRIMARY KEY(piste_name, lift_name)
);
so if i insert some values into these tables:
INSERT INTO lift (lift_name, lift_type, summit, rise, length, operating) VALUES
('test lift', 'gondola', 1920, 440, 1600, true);
INSERT INTO piste (piste_name, grade, length, fall, open) VALUES
('test piste, 'medium', 3, 440, true);
These tables will one row with the specified information. based on the above i want my lift_location table to have the following information:
piste_name | lift_name
________________________
test piste | test lift
How can i accomplish this?
Thanks.
Chris.
You need to run an additional query. You need add a new row to the lift_location table to create the relationship between the two rows in the two tables.
INSERT INTO lift_location (piste_name, lift_name) VALUES ('test piste', 'test lift');
Also make sure both lift and piste tables have the required test data. You're missing a ' in your second INSERT query.

SQL table display error

I am encountering a display issue with my SQL code and was hoping someone could help me figure out whats going on. When I create my CUSTOMER table then INSERT a line of values it works successfully... however, when I type select * from customer; then it displays horrible output where none of the data is lined up in the columns properly. Can you please take a look at my code and tell me what I can do to fix this.
I have multiple tables in this database and none of the other tables have this issue and display properly. My window was configured using these two lines of code:
SET LINESIZE 132
SET PAGESIZE 50
My table creation code:
CREATE TABLE Customer
(
CustomerID NUMBER(5) NOT NULL CONSTRAINT PK_Customer_CustomerID PRIMARY KEY,
BillingID NUMBER(5) NOT NULL,
CustomerFName VARCHAR2(40) NOT NULL,
CustomerLName VARCHAR2(40) NOT NULL,
CustomerPhone VARCHAR2(10) NOT NULL,
CustomerStreet VARCHAR2(30)NOT NULL,
CustomerCity VARCHAR2(30) NOT NULL,
CustomerState CHAR(2) NOT NULL,
CustomerZip VARCHAR2(9) NOT NULL,
CustomerEmail VARCHAR2(75) NOT NULL,
SignUp_Date DATE DEFAULT sysdate NOT NULL,
CustomerStatus CHAR(1) NOT NULL CONSTRAINT CC_Customer_CustomerStatus CHECK (CustomerStatus IN ('A', 'I')),
InactiveDate DATE,
InactiveReason VARCHAR2(200),
CustomerBillingCycle CHAR(1) NOT NULL CONSTRAINT CC_Customer_CustomerBC CHECK (CustomerBillingCycle IN ('A', 'B'))
);
My line of values being inserted into the table:
INSERT INTO Customer VALUES (01234, 99012, 'Michael', 'Huffaker', '6235551414', '65 N 35th Ln', 'Glendale', 'AZ', '85308', 'm.huffaker#quickmail.com', '29-MAY-2010', 'A', NULL, NULL, 'A');
As I stated above, both of these work successfully and the problem appears when I display the data in the table. Check out the screen shot link below to see the messed up output:
http://i.stack.imgur.com/uMu4S.png
It's not messed up at all; the output lines are just "wrapping" the output after 132 characters. It's very normal. I don't use command line often for running selects, but try routing the output to a file. Or perhaps try with a very large LINESIZE setting (like 1000 or so). Your terminal windows may not support a line that wide.

Ensuring uniqueness of multiple large URL fields in MS SQL

I have a table with the following definition:
CREATE TABLE url_tracker (
id int not null identity(1, 1),
active bit not null,
install_date int not null,
partner_url nvarchar(512) not null,
local_url nvarchar(512) not null,
public_url nvarchar(512) not null,
primary key(id)
);
And I have a requirement that these three URLs always be unique - any individual URL can appear many times, but the combination of the three must be unique (for a given day).
Initially I thought I could do this:
CREATE UNIQUE INDEX uniques ON url_tracker
(install_date, partner_url, local_url, public_url);
However this gives me back the warning:
Warning! The maximum key length is 900 bytes. The index 'uniques' has maximum
length of 3076 bytes. For some combination of large values, the insert/update
operation will fail.
Digging around I learned about the INCLUDE argument to CREATE INDEX, but according to this question converting the command to use INCLUDE will not enforce uniqueness on the URLs.
CREATE UNIQUE INDEX uniques ON url_tracker (install_date)
INCLUDE (partner_url, local_url, public_url);
How can I enforce uniqueness on several relatively large nvarchar fields?
Resolution
So from the comments and answers and more research I'm concluding I can do this:
CREATE TABLE url_tracker (
id int not null identity(1, 1),
active bit not null,
install_date int not null,
partner_url nvarchar(512) not null,
local_url nvarchar(512) not null,
public_url nvarchar(512) not null,
uniquehash AS HashBytes('SHA1',partner_url+local_url+public_url) PERSISTED,
primary key(id)
);
CREATE UNIQUE INDEX uniques ON url_tracker (install_date,uniquehash);
Thoughts?
I would make a computed column with the hash of the URLs, then make a unique index/constraint on that. Consider making the hash a persisted computed column. It shouldn't have to be recalculated after insertion.
Following the ideas from the conversation in the comments. Assuming that you can change the datatype of the URL to be VARCHAR(900) (or NVARCHAR(450) if you really think you need Unicode URLs) and be happy with the limitation on the length of the URL, this solution could work. This also assumes SQL Server 2008 or better. Please, always specify what version you're working with; sql-server is not specific enough, since solutions can vary greatly depending on the version.
Setup:
USE tempdb;
GO
CREATE TABLE dbo.urls
(
id INT IDENTITY(1,1) PRIMARY KEY,
url VARCHAR(900) NOT NULL UNIQUE
);
CREATE TABLE dbo.url_tracker
(
id INT IDENTITY(1,1) PRIMARY KEY,
active BIT NOT NULL DEFAULT 1,
install_date DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
partner_url_id INT NOT NULL REFERENCES dbo.urls(id),
local_url_id INT NOT NULL REFERENCES dbo.urls(id),
public_url_id INT NOT NULL REFERENCES dbo.urls(id),
CONSTRAINT unique_urls UNIQUE
(
install_date,partner_url_id, local_url_id, public_url_id
)
);
Insert some URLs:
INSERT dbo.urls(url) VALUES
('http://msn.com/'),
('http://aol.com/'),
('http://yahoo.com/'),
('http://google.com/'),
('http://gmail.com/'),
('http://stackoverflow.com/');
Now let's insert some data:
-- succeeds:
INSERT dbo.url_tracker(partner_url_id, local_url_id, public_url_id)
VALUES (1,2,3), (2,3,4), (3,4,5), (4,5,6);
-- fails:
INSERT dbo.url_tracker(partner_url_id, local_url_id, public_url_id)
VALUES(1,2,3);
GO
/*
Msg 2627, Level 14, State 1, Line 3
Violation of UNIQUE KEY constraint 'unique_urls'. Cannot insert duplicate key
in object 'dbo.url_tracker'. The duplicate key value is (2011-09-15, 1, 2, 3).
The statement has been terminated.
*/
-- succeeds, since it's for a different day:
INSERT dbo.url_tracker(install_date, partner_url_id, local_url_id, public_url_id)
VALUES('2011-09-01',1,2,3);
Cleanup:
DROP TABLE dbo.url_tracker, dbo.urls;
Now, if 900 bytes is not enough, you could change the URL table slightly:
CREATE TABLE dbo.urls
(
id INT IDENTITY(1,1) PRIMARY KEY,
url VARCHAR(2048) NOT NULL,
url_hash AS CONVERT(VARBINARY(32), HASHBYTES('SHA1', url)) PERSISTED,
CONSTRAINT unique_url UNIQUE(url_hash)
);
The rest doesn't have to change. And if you try to insert the same URL twice, you get a similar violation, e.g.
INSERT dbo.urls(url) SELECT 'http://www.google.com/';
GO
INSERT dbo.urls(url) SELECT 'http://www.google.com/';
GO
/*
Msg 2627, Level 14, State 1, Line 1
Violation of UNIQUE KEY constraint 'unique_url'. Cannot insert duplicate key
in object 'dbo.urls'. The duplicate key value is
(0xd111175e022c19f447895ad6b72ff259552d1b38).
The statement has been terminated.
*/