Having viewed several matrials both here on Stack Overflow and other external sources, I am attempting to write a piece of code to generate a view that performs a calculation utilising data from other tables, The aim of the code is:
To Acquire username from the UserDetails table
Acquire weight in pounds from the UserDetails Table
Acquire distance_in_miles from the Cardiovascular Records table
Use the weight and distance in a calculation as shown below which is output as the caloriesBurned column.
My attempt can be seen below:
CREATE VIEW CardioCaloriesBurned (username, weight, distance, caloriesBurned) AS
SELECT UserDetails.username, UserDetails.weight_in_pounds,
CardiovascularRecords.distance_in_miles ,
((0.75 X weight_in_pounds) X distance_in_miles)
FROM UserDetails, CardiovascularRecords
If anyone could help in correcting this issue It would be greatly appreciated.
Edit: I am getting a syntax error in SQLite Manager relating to a "(" however Im not seeing any issues myself.
Edit: Code for the Cardiovascular Table and UserDetails table below:
CREATE TABLE "CardiovascularRecords" ("record_ID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE CHECK (record_ID>0) , "distance_in_miles" REAL NOT NULL CHECK (distance_in_miles>0) , "username" TEXT NOT NULL , "date" DATETIME DEFAULT CURRENT_DATE, "notes" TEXT(50), "start_time" TEXT, "end_time" TEXT, FOREIGN KEY(distance_in_miles) REFERENCES DistanceinMiles(distance_in_miles) ON DELETE CASCADE ON UPDATE CASCADE,FOREIGN KEY(username) REFERENCES UserDetails(username) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE TABLE "UserDetails" ("username" TEXT PRIMARY KEY NOT NULL UNIQUE CHECK (length(username)>0), "password" TEXT NOT NULL CHECK (length(password)>3), "email_address" TEXT NOT NULL UNIQUE CHECK (length(email_address)>3) , "weight_in_pounds" REAL NOT NULL CHECK(weight_in_pounds>0) CHECK (length(weight_in_pounds)>0), "height_in_inches" REAL NOT NULL CHECK(height_in_inches>0) CHECK (length(height_in_inches)>0), "age" INTEGER CHECK(age>0), WITHOUT ROWID)
Thanks
JHB92
Your immediate error message is probably caused by the fact that you're using the letter X to indicate multiplication. It should be * (the capital 8 character on US keyboards).
After you've solved that problem, you may find that you have many, many more results in the output than you expect. That's because you're not telling the database which record in CardiovascularRecords to "hook up" for the purpose of doing the calculation. That may or may not (probably not) produce the results you want.
If you're not getting what you want, you must tell us which column or columns in UserDetails "point to" the record in CardiovascularRecords that applies to any given calculation.
CREATE VIEW CardioCaloriesBurned AS
SELECT UserDetails.username AS username,
UserDetails.weight_in_pounds AS weight,
CardiovascularRecords.distance_in_miles AS distance,
((0.75 * weight_in_pounds) * distance_in_miles) AS caloriesBurned
FROM UserDetails INNER JOIN CardiovascularRecords
ON UserDetails.username = CardiovascularRecords.username
Related
I'm new to Sql and want to use sqlite to create a database to store data about which topics are needed by which exam boards.
So far I've created two tables - one called board and one called topic. I'm not sure how I should represent the relationship between boards and topics. I have read a bit about Normal Form, and I'm pretty sure that I shouldn't be putting multiple entries into one field, and also that having fields like topic1, topic2 etc. is not the way to go.
My sql so far is below. Could someone please help me with the next step - how to make this database actually work for my requirements while not breaking every rule in the book?
For example, I'd like to be able to quickly find out which boards require knowledge of set theory or reciprocal functions etc.
Thanks in advance.
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "topic" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"topic_name" TEXT NOT NULL,
"level" INTEGER
);
CREATE TABLE IF NOT EXISTS "board" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"board_name" TEXT NOT NULL UNIQUE,
"link_to_syllabus" TEXT
);
INSERT INTO "topic" ("id","topic_name","level") VALUES (1,'Pythagoras'' Theorem','F');
INSERT INTO "topic" ("id","topic_name","level") VALUES (2,'Circle theorems','H');
INSERT INTO "topic" ("id","topic_name","level") VALUES (3,'',NULL);
INSERT INTO "board" ("id","board_name","link_to_syllabus") VALUES (0,'Edexcel','https://qualifications.pearson.com/en/qualifications/edexcel-gcses/mathematics-2015.html');
INSERT INTO "board" ("id","board_name","link_to_syllabus") VALUES (1,'OCR','https://www.ocr.org.uk/qualifications/gcse/mathematics-j560-from-2015/');
COMMIT;
If I understood, a board can have one or more topic, and a topic can be in one or more boards. If it is correct, you are searching for a many to many relationship, wich is obtained with the table:
CREATE TABLE board_topic (
board_id INTEGER NOT NULL
REFERENCES topic (id),
topic_id INTEGER NOT NULL
REFERENCES board (id),
CONSTRAINT pk PRIMARY KEY (
board_id ,
topic_id
)
)
About the query you asked for, after you insert some data into the association table just showed, the query looks like:
SELECT board.id, board_name FROM board
JOIN board_topic ON board.id = board_topic.board_id
JOIN topic ON topic.id = board_topic.topic_id
WHERE topic_name = "Circle theorems";
Similar to this question and this solution for PostgreSQL (in particular "INSERT missing FK rows at the same time"):
Suppose I am making an address book with a "Groups" table and a "Contact" table. When I create a new Contact, I may want to place them into a Group at the same time. So I could do:
INSERT INTO Contact VALUES (
"Bob",
(SELECT group_id FROM Groups WHERE name = "Friends")
)
But what if the "Friends" Group doesn't exist yet? Can we insert this new Group efficiently?
The obvious thing is to do a SELECT to test if the Group exists already; if not do an INSERT. Then do an INSERT into Contacts with the sub-SELECT above.
Or I can constrain Group.name to be UNIQUE, do an INSERT OR IGNORE, then INSERT into Contacts with the sub-SELECT.
I can also keep my own cache of which Groups exist, but that seems like I'm duplicating functionality of the database in the first place.
My guess is that there is no way to do this in one query, since INSERT does not return anything and cannot be used in a subquery. Is that intuition correct? What is the best practice here?
My guess is that there is no way to do this in one query, since INSERT
does not return anything and cannot be used in a subquery. Is that
intuition correct?
You could use a Trigger and a little modification of the tables and then you could do it with a single query.
For example consider the folowing
Purely for convenience of producing the demo:-
DROP TRIGGER IF EXISTS add_group_if_not_exists;
DROP TABLE IF EXISTS contact;
DROP TABLE IF EXISTS groups;
One-time setup SQL :-
CREATE TABLE IF NOT EXISTS groups (id INTEGER PRIMARY KEY, group_name TEXT UNIQUE);
INSERT INTO groups VALUES(-1,'NOTASSIGNED');
CREATE TABLE IF NOT EXISTS contact (id INTEGER PRIMARY KEY, contact TEXT, group_to_use TEXT, group_reference TEXT DEFAULT -1 REFERENCES groups(id));
CREATE TRIGGER IF NOT EXISTS add_group_if_not_exists
AFTER INSERT ON contact
BEGIN
INSERT OR IGNORE INTO groups (group_name) VALUES(new.group_to_use);
UPDATE contact SET group_reference = (SELECT id FROM groups WHERE group_name = new.group_to_use), group_to_use = NULL WHERE id = new.id;
END;
SQL that would be used on an ongoing basis :-
INSERT INTO contact (contact,group_to_use) VALUES
('Fred','Friends'),
('Mary','Family'),
('Ivan','Enemies'),
('Sue','Work colleagues'),
('Arthur','Fellow Rulers'),
('Amy','Work colleagues'),
('Henry','Fellow Rulers'),
('Canute','Fellow Ruler')
;
The number of values and the actual values would vary.
SQL Just for demonstration of the result
SELECT * FROM groups;
SELECT contact,group_name FROM contact JOIN groups ON group_reference = groups.id;
Results
This results in :-
1) The groups (noting that the group "NOTASSIGNED", is intrinsic to the working of the above and hence added initially) :-
have to be careful regard mistakes like (Fellow Ruler instead of Fellow Rulers)
-1 used because it would not be a normal value automatically generated.
2) The contacts with the respective group :-
Efficient insertion
That could likely be debated from here to eternity so I leave it for the fence sitters/destroyers to decide :). However, some considerations:-
It works and appears to do what is wanted.
It's a little wasteful due to the additional wasted column.
It tries to minimise the waste by changing the column to an empty string (NULL may be even more efficient, but for some can be confusing)
There will obviously be an overhead BUT in comparison to the alternatives probably negligible (perhaps important if you were extracting every Facebook user) but if it's user input driven likely irrelevant.
What is the best practice here?
Fences again. :)
Note Hopefully obvious, but the DROP statements are purely for convenience and that all other SQL up until the INSERT is run once
to setup the tables and triggers in preparation for the single INSERT
that adds a group if necessary.
I am currently working on a database structure in SQLite Studio (not sure whether that's in itself important, but might as well mention), and error messages are making me wonder whether I'm just going at it the wrong way or there's some subtlety I'm missing.
Assume two tables, people-basics (person-ID, person-NAME, person-GENDER) and people-stats (person-ID, person-NAME, person-SIZE). What I'm looking into achieving is "Every record in people-basics corresponds to a single record in people-stats.", ideally with the added property that person-ID and person-NAME in people-stats reflect the associated person-ID and person-NAME in people-basics.
I've been assuming up to now that one would achieve this with Foreign Keys, but I've also been unable to get this to work.
When I add a person in people-basics, it works fine, but then when I go over to people-stats no corresponding record exists and if I try to create one and fill the Foreign Key column with corresponding data, I get this message: "Cannot edit this cell. Details: Error while executing SQL query on database 'People': no such column: people-basics.person" (I think the message is truncated).
The DDL I currently have for my tables (auto-generated by SQLite Studio based on my GUI operations):
CREATE TABLE [people-basics] (
[person-ID] INTEGER PRIMARY KEY AUTOINCREMENT
UNIQUE
NOT NULL,
[person-NAME] TEXT UNIQUE
NOT NULL,
[person-GENDER] TEXT
);
CREATE TABLE [people-stats] (
[person-NAME] TEXT REFERENCES [people-basics] ([person-NAME]),
[person-SIZE] NUMERIC
);
(I've removed the person-ID column from people-stats for now as it seemed like I should only have one foreign key at a time, not sure whether that's true.)
Alright, that was a little silly.
The entire problem was solved by removing hyphens from table names and column names. (So: charBasics instead of char-basics, etc.)
Ah well.
I'm not sure that I'm getting an id primary key in my sqlite table.
When I create my table I use
CREATE TABLE IF NOT EXISTS HABITS (id unique, uid, text, orglvl, habitstatus)
The other properties are fine, and I can retrieve results.rows.item(i).text, but results.rows.item(i).id is NULL
Also upon Insert, when I try to get results.insertId, I get an error of "undefined", which started this whole wondering for me.
What am I doing wrong - how come I have no id's when I have created them in my table?
To get an autoincrementing column, you must use INTEGER PRIMARY KEY.
I have a problem with a sqlite command.
I have a table with three columns: Id, user, number.
The id is continuing. Now if I put a user and a number inside my list, my app should compare if such a user with this number already exist. The problem is, if I use a standard "insert or ignore" command, the Id column is not fixed, so I will get a new entry every time.
So is it possible just two compare two of three columns if they are equal?
Or do I have to use a temporary list, where are only two columns exist?
The INSERT OR IGNORE statement ignores the new record if it would violate a UNIQUE constraint.
Such a constraint is created implicitly for the PRIMARY KEY, but you can also create one explicitly for any other columns:
CREATE TABLE MyTable (
ID integer PRIMARY KEY,
User text,
Number number,
UNIQUE (User, Number)
);
You shouldn't use insert or ignore unless you are specifying the key, which you aren't and in my opinion never should if your key is an Identity (Auto number).
Based on User and Number making a record in your table unique, you don't need the id column and your primary key should be user,number.
If for some reason you don't want to do that, and bearing in mind in that case you are saying that User,Number is not your uniqueness constraint then something like
if not exists(Select 1 From MyTable Where user = 10 and Number = 15)
Insert MyTable(user,number) Values(10,15)
would do the job. Not a SqlLite boy, so you might have to rwiddle with the syntax and wrap escape your column names.