I am relativity new to sql and need some help.
I have a table called TREATMENT which has 2 fields:
T_ID(primary key)
T_NAME.
Some of these treatments should not be used with others. For example.. if T_ID = 'T001' is used with T_ID = 'T002' it will cause severe headaches. and I want to do this for a few of them.
So I need the PL/SQL to take a value from the user and which a T_ID and the program will output the colliding treatment.
thanks in advance
this is my table:
DROP TABLE TREATMENT CASCADE CONSTRAINTS;
CREATE TABLE TREATMENT(
T_ID VARCHAR2(5) PRIMARY KEY NOT NULL,
T_NAME VARCHAR2(15));
INSERT INTO TREATMENT VALUES
('T001','ACCUPUNCTURE');
INSERT INTO TREATMENT VALUES
('T002','MASSAGE');
INSERT INTO TREATMENT VALUES
('T003','SKIN CARE');
INSERT INTO TREATMENT VALUES
('T004','OSTEOPATHY');
INSERT INTO TREATMENT VALUES
('T005','HOMOEOPATHY');
INSERT INTO TREATMENT VALUES
('T006','PHYSIOTHERAPY');
INSERT INTO TREATMENT VALUES
('T007','PSYCHOLOGY');
INSERT INTO TREATMENT VALUES
('T008','DEMATOLOGY');
INSERT INTO TREATMENT VALUES
('T009','YOGA');
commit;
I want for example to restrict "yoga" and "dermatology" from being taken together as they will have side effects like. user inputs T009 and system replies... yoga should not be taken with dermatology. will cause headache
This is a data modelling problem. You need another table to hold banned combinations. Eg.
create table contraindication
( treatment1 VARCHAR2(5)
, treatment2 VARCHAR2(5)
, primary key ci_pk (treatment1, treatment2) );
insert into contraindication values ('T008', 'T009');
Your procedure should look up this table.
You may find it helpful to insert both permutations, as this will make the query simpler (and more efficient if the list gets big):
insert into contraindication values ('T009', 'T008');
Related
I'm trying to create 3 access tables in SQL view on Microsoft Access but whenever I try to execute it, I receive the following error. 'Syntax Error in CREATE TABLE statement'.
Please find my code below.
CREATE TABLE Book (
Book_ID int,
Book_Title varchar (30),
PRIMARY KEY (Book_ID)
);
CREATE TABLE Users (
User_ID int,
User_Name varchar (30),
PRIMARY KEY (User_ID)
);
CREATE TABLE Borrows (
User_ID int,
Book_ID int,
B_ID int,
PRIMARY KEY(B_ID),
FOREIGN KEY(User_ID) REFERENCES Users(User_ID),
FOREIGN KEY(Book_ID) REFERENCES Book(Book_ID)
);
INSERT INTO Book VALUES (101, 'The Hobbit'), (102, 'To Kill a Mockingbird');
INSERT INTO Users VALUES (1, 'Stephen'), (2, 'Tom'), (3,' Eric');
INSERT INTO Borrows VALUES (3, 102, 1), (1, 101, 2);
Appreciate any feedback I can get, have a good day.
Your first CREATE TABLE executed flawlessly from the query designer in Access 2010. However my preference is to include the PRIMARY KEY constraint as part of the field definition:
CREATE TABLE Book (
Book_ID int PRIMARY KEY,
Book_Title varchar (30)
);
That variation also executed successfully.
I suspect you have at least 2 issues to resolve:
Access does not allow you to execute more than one SQL statement at a time (as Heinzi and Albert mentioned). You must execute them one at a time.
In Access, INSERT ... VALUES can only be used to add one row at a time. Revise your inserts accordingly.
IOW, split the first one into 2 statements which you then execute individually:
-- INSERT INTO Book VALUES (101, 'The Hobbit'), (102, 'To Kill a Mockingbird');
INSERT INTO Book VALUES (101, 'The Hobbit');
INSERT INTO Book VALUES (102, 'To Kill a Mockingbird');
Then split and execute the remaining inserts similarly.
Your code example use SQL Server (T-SQL) syntax, not MS Access syntax.
The syntax for Access' CREATE TABLE statement is documented here:
https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/create-table-statement-microsoft-access-sql
The most obvious differences seem to be there is no varchar type and that PRIMARY KEY needs a constraint name if specified in an extra line. There might be more, see the article and its examples for details. I also suggest that you submit your statements one-by-one, instead of submitting a complete ;-separated batch; I'm not sure Access queries even support the latter.
I have started my journey in learning SQL and right I am having trouble creating and inserting data into tables. Here is the code that I have tried, I get an error message saying that there aren't enough values. I am using Oracle.
Create table project
(
proj_id number(10),
medic_name varchar2(10),
purpose varchar2(12),
start_date date,
end_date date,
pi_id null,
CONSTRAINT pkprojid primary key (proj_id),
CONSTRAINT fkproject foreign key (pi_id) references researcher
);
alter session set nls_date_format = 'mm/dd/yyyy';
Insert into project values (PR001, 'Medic1', 'heart', '09/01/2017', '07/31/2019');
Insert into project values (PR002, 'Medic1', 'diabetes', '10/01/2016', '07/31/2020);
Insert into project values (PR003, 'Medic3', 'lung', '11/1/2014', '12/31/2020');
Insert into project values (PR004, 'Medic3', 'blood', '01/10/2017', '07/31/2019');
Insert into project values (PR005, 'Medic5', 'blood', '07/10/2018', '01/31/2020');
alter session set nls_date_format = 'mm/dd/yyyy';
Insert into project values (PR001, 'Medic1', 'heart', '09/01/2017', '07/31/2019');
Issues:
Your table has 6 columns, you are only passing 5 for insert; it seems like you are missing last column (pi_id), hence the error message that you are getting. If you want to skip the last column (which is possible since it is declared as nullable), you can explictly list the column when inserting
first column (proj_id) is of number datatype; PR001 is not a number (neither a string, since it is not quoted: this is a syntax error); did you mean 1 instead? Or, if you want to insert string values, you need to change the datatype of column proj_id to varchar(N) (N being the maximum length of the string, in bytes).
Here is an insert statement that should work for your current table definition:
insert into project(proj_id, medic_name, purpose, start_date, end_date)
values (1, 'Medic1', 'heart', '09/01/2017', '07/31/2019');
Note: there is a missing quote at the end of the date on the second insert statement; I assume that this is a typo.
So let's say I have these two tables...
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='UnitsDef' AND xtype='U')
CREATE TABLE UnitsDef
(
UnitsID INTEGER PRIMARY KEY,
UnitsName NVARCHAR(32) NOT NULL,
UnitsDisplay NVARCHAR(8) NOT NULL
);
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Dimensions' AND xtype='U')
CREATE TABLE Dimensions
(
DimID INTEGER PRIMARY KEY IDENTITY(0,1),
DimX FLOAT,
DimXUnitsID INTEGER DEFAULT 0,
DimY FLOAT,
DimYUnitsID INTEGER DEFAULT 0,
DimZ FLOAT,
DimZUnitsID INTEGER DEFAULT 0,
FOREIGN KEY (DimXUnitsID) REFERENCES UnitsDef(UnitsID),
FOREIGN KEY (DimYUnitsID) REFERENCES UnitsDef(UnitsID),
FOREIGN KEY (DimZUnitsID) REFERENCES UnitsDef(UnitsID)
);
I'll insert data into the first table similar to this...
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (0, 'inch', 'in.');
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (1, 'millimeter', 'mm');
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (2, 'degree', '°');
Am I going about this the right way? This is a simplified version of the problem, but I need to know which unit each measurement is given in. Is there a better design practice for this type of situation?
How would I handle the ON DELETE and ON UPDATE for these foreign keys? If I try to cascade deletes and updates, SQL Server would not be so happy about that.
Your method is pretty good. I would make the suggestion right off that UnitsId be an identity column, so it gets incremented. Your inserts would then be:
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('inch', 'in.');
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('millimeter', 'mm');
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('degree', '°');
You should also make the string columns unique in UnitsDef and give them case-sensitive collations. After all, Ml and ml are two different things ("M" is mega and "m" is milli).
You might also want to combine the units and values into a single type. This has positives and negatives. For me it adds overhead, but it can help if you want to support a fuller algebra of types.
I have a sample table like below where Course Completion Status of a Student is being stored:
Create Table StudentCourseCompletionStatus
(
CourseCompletionID int primary key identity(1,1),
StudentID int not null,
AlgorithmCourseStatus nvarchar(30),
DatabaseCourseStatus nvarchar(30),
NetworkingCourseStatus nvarchar(30),
MathematicsCourseStatus nvarchar(30),
ProgrammingCourseStatus nvarchar(30)
)
Insert into StudentCourseCompletionStatus Values (1, 'In Progress', 'In Progress', 'Not Started', 'Completed', 'Completed')
Insert into StudentCourseCompletionStatus Values (2, 'Not Started', 'In Progress', 'Not Started', 'Not Applicable', 'Completed')
Now as part of normalizing the schema I have created two other tables - CourseStatusType and Status for storing the Course Status names and Status.
Create Table CourseStatusType
(
CourseStatusTypeID int primary key identity(1,1),
CourseStatusType nvarchar(100) not null
)
Insert into CourseStatusType Values ('AlgorithmCourseStatus')
Insert into CourseStatusType Values ('DatabaseCourseStatus')
Insert into CourseStatusType Values ('NetworkingCourseStatus')
Insert into CourseStatusType Values ('MathematicsCourseStatus')
Insert into CourseStatusType Values ('ProgrammingCourseStatus')
Insert into CourseStatusType Values ('OperatingSystemsCourseStatus')
Insert into CourseStatusType Values ('CompilerCourseStatus')
Create Table Status
(
StatusID int primary key identity(1,1),
StatusName nvarchar (100) not null
)
Insert into Status Values ('Completed')
Insert into Status Values ('Not Started')
Insert into Status Values ('In Progress')
Insert into Status Values ('Not Applicable')
The modified table is as below:
Create Table StudentCourseCompletionStatus1
(
CourseCompletionID int primary key identity(1,1),
StudentID int not null,
CourseStatusTypeID int not null CONSTRAINT [FK_StudentCourseCompletionStatus1_CourseStatusType] FOREIGN KEY (CourseStatusTypeID) REFERENCES dbo.CourseStatusType (CourseStatusTypeID),
StatusID int not null CONSTRAINT [FK_StudentCourseCompletionStatus1_Status] FOREIGN KEY (StatusID) REFERENCES Status (StatusID),
)
I have few question on this:
Is this the correct way to normalize it ? The old table was very helpful to get data easily - I can store a student's course status in a single row, but now 5 rows are required. Is there a better way to do it?
Moving the data from the old table to this new table seems to be not an easy task. Can I achieve this using a query or I have to manually to do this ?
Any help is appreciated.
vou could also consider storing results in flat table like this:
studentID,courseID,status
1,1,"completed"
1,2,"not started"
2,1,"not started"
2,3,"in progress"
you will also need additional Courses table like this
courserId,courseName
1, math
2, programming
3, networking
and a students table
students
1 "john smith"
2 "perry clam"
3 "john deere"
etc..you could also optionally create a status table to store the distinct statusstrings statusstings and refer to their PK instead ofthestrings
studentID,courseID,status
1,1,1
1,2,2
2,1,2
2,3,3
... etc
and status table
id,status
1,"completed"
2,"not started"
3,"in progress"
the beauty of this representation is: it is quite easy to filter and aggregate data , i.e it is easy to query which subjects a particular person have completed, how many subjects are completed by an average student, etc. this things are much more difficult in the columnar design like you had. you can also easily add new subjects without the need to adapt your tables or even queries they,will just work.
you can also always usin SQLs PIVOT query to get it to a familiar columnar presentation like
name,mathstatus,programmingstatus,networkingstatus,etc..
but now 5 rows are required
No, it's still just one row. That row simply contains identifiers for values stored in other tables.
There are pros and cons to this. One of the main reasons to normalize in this way is to protect the integrity of the data. If a column is just a string then anything can be stored there. But if there's a foreign key relationship to a table containing a finite set of values then only one of those options can be stored there. Additionally, if you ever want to change the text of an option or add/remove options, you do it in a centralized place.
Moving the data from the old table to this new table seems to be not an easy task.
No problem at all. Create your new numeric columns on the data table and populate them with the identifiers of the lookup table records associated with each data table record. If they're nullable, you can make them foreign keys right away. If they're not nullable then you need to populate them before you can make them foreign keys. Once you've verified that the data is correct, remove the old de-normalized columns. Done.
In StudentCourseCompletionStatus1 you still need 2 associations to Status and CourseStatusType. So I think you should consider following variant of normalization:
It means, that your StudentCourseCompletionStatus would hold only one CourseStatusID and another table CourseStatus would hold the associations to CourseType and Status.
To move your data you can surely use a query.
I want to know how can I add a DB restriction on a table. I want to simplify the problem with a table in Oracle Database as
CREATE TABLE TEST_STUDENT
(
STUDENT VARCHAR2(30 CHAR),
SUBJECT VARCHAR2(38) ,
IS_LANG NUMBER(1,0)
);
A student can have any number of subjects but only one of them can be a language (IS_LANG).
Valid data would be
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('John','Math',);
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('John','Science',);
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('John','French',1);
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('Lily','Math',);
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('Lily','English',1);
however, I should not be able to insert fresh data like up the table, something like
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('John','English',1);
or
Insert into TEST_STUDENT (STUDENT,SUBJECT,IS_LANG) values ('Lily','French',1);
I don't want to introduce triggers here, unless it is the only way around. I want to have this restrictions because in the actual software would have multiple client implementations trying to insert data into this table.
This one of the good examples for a partial index.
Unfortunately in Oracle you need a workaround to implement a partial index (other DBMS simply allow a WHERE clause to be applied):
create unique index idx_one_language
on test_student
(
case when is_lang = 1 then student else null end
);
This exploits the fact that Oracle does not index tuples where all columns are null. With the above expression only rows where IS_LANG = 1 will be indexed for each student. As the index is defined as unique, only one such row can exist.
Here is a SQLFiddle example: http://sqlfiddle.com/#!4/43394d/1