I have made a simple relation table. All consist of three tables:
Tables for storing personal data (Table_Person)
Table for storing address data (Table_Address)
Table to store the relationship between Table_Person and Table_Address (Table_PersonAddress).
What I want to ask is can I delete the primary key in Table_PersonAddress so that Table_PersonAddress doesn't have a primary key and all that's left is the personID and addressID?
Below is an example of a database relation that I made:
enter image description here
Assuming you don't have any foreign key constraints setup on the junction table (that is, the third table which just stores relationships between people and their addresses), you could delete a person from the first table, while leaving behind the relationships in the third table. However, just because you could do this, does not mean you would want to. Most of the time, if you remove a person from the first table, you would also want to remove all of his relationships from the third table. One way to do this in SQLite is by adding cascading delete constraints to the third table, when you create it:
CREATE TABLE Table_PersonAddress (
...
CONSTRAINT fk_person
FOREIGN KEY (personID)
REFERENCES Table_Person (ID)
ON DELETE CASCADE
)
You probably would also want to add a similar constraint for the address field in the third table, since removing an address also invalidates all relationships involving that address.
Note that SQLite does not allow a cascading delete constraint to be added to table which already exists. You will have to recreate your tables somehow in order to add these constrains.
You can delete it, but my advice is to set a composite PRIMARY KEY for the 2 columns personID and addressID so each row is guaranteed to be UNIQUE.
PRIMARY KEY (personID, addressID)
and remember that in SQLite you always have the rowid column to use it as an id of the row if needed.
So create the table with this statement:
DROP TABLE IF EXISTS PersonAddress;
CREATE TABLE PersonAddress (
personID INTEGER,
addressID INTEGER,
PRIMARY KEY(personID, addressID),
FOREIGN KEY (personID) REFERENCES Person (personID) ON DELETE CASCADE,
FOREIGN KEY (addressID) REFERENCES Address (addressID) ON DELETE CASCADE
);
One more thing: why did you define personID and addressID as TEXT?
Surely SQLite is not at all strict at data type definitions, but since the columns they reference are INTEGER they also should be INTEGER.
Related
My issue is that I am getting a foreign key constraint error when I try to add a column to a table. Not a row, a column!
My table is called Screens. It has two tables with foreign key dependencies. They are called Topic and ScreenTypes. Both tables are very small and they only have 2 columns each (id and name). The Screens table contains the columns TopicId and ScreenTypeId plus a couple of other columns. All three table have primary indexes. Everything has been working fine for the past few weeks.
Then, I tried to add a new column to the Screens table called ScreenNumber. The new column is numeric and has no restrictions whatsoever. But, when I tried to commit the change to the schema, I got a foreign key constraint error.
I thought I would get around it by removing the foreign key constraint, adding the column and then adding the foreign key constraint back. But, when I tried to remove the foreign key constraint, I got another foreign key constraint error.
Any help would be greatly appreciated! I have no idea what is causing this and I am past my deadline for this project.
My table is called Screens. It has two tables with foreign key
dependencies. They are called Topic and ScreenTypes. Both tables are
very small and they only have 2 columns each (id and name). The
Screens table contains the columns TopicId and ScreenTypeId plus a
couple of other columns. All three table have primary indexes.
Everything has been working fine for the past few weeks.
From the above and your comments then this appears to create the Screens Table, the Topics Table and the ScreenTypes table and additionally populate the tables with some data:-
DROP TABLE IF EXISTS Screens;
CREATE TABLE IF NOT EXISTS Screens (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
Video TEXT NOT NULL,
TopicId INTEGER NOT NULL,
Instructions TEXT,
ScreenTypeId INTEGER,
SortOrder INTEGER DEFAULT (10),
Image TEXT,
NewColumn INTEGER,
FOREIGN KEY (TopicId) REFERENCES Topics (id),
FOREIGN KEY (ScreenTypeId) REFERENCES ScreenTypes (id)
)
;
DROP TABLE IF EXISTS Topics;
CREATE TABLE IF NOT EXISTS Topics (ID INTEGER PRIMARY KEY, name TEXT);
DROP TABLE IF EXISTS ScreenTypes;
CREATE TABLE IF NOT EXISTS ScreenTypes (ID INTEGER PRIMARY KEY, name TEXT);
INSERT INTO Topics (name) VALUES ('Topic1'),('Topic2'),('Topic3'),('Topic4');
INSERT INTO ScreenTypes (name) VALUES ('SreenType1'),('ScreenType2'),('ScreenType3'),('ScreenType4');
INSERT INTO Screens (Video,TopicId,Instructions,ScreenTypeId,Image,NewColumn) VALUES
('Video1',2,'do this 001',3,'Image1','blah'),
('Video2',2,'do this 002',3,'Image2','blah'),
('Video3',1,'do this 002',1,'Image3','blah'),
('Video4',3,'do this 004',4,'Image4','blah'),
('Video5',4,'do this 005',1,'Image5','blah')
;
Then, I tried to add a new column to the Screens table called
ScreenNumber. The new column is numeric and has no restrictions
whatsoever. But, when I tried to commit the change to the schema, I
got a foreign key constraint error.
The following works :-
ALTER TABLE Screens ADD COLUMN ScreenNumber INTEGER DEFAULT 100;
as per :-
ALTER TABLE Screens ADD COLUMN ScreenNumber INTEGER DEFAULT 100
OK
Time: 0.083s
and then using the following
SELECT * FROM Screens;
The result is :-
As can be seen, there were no FK constraint conflicts and the column has been added and the default value of 100 applied.
I suspect that your issues with FK Constraints is that you are progressively try to correct issues.
First (at a guess) you try altering (renaming) the Screens table but can't because of the Fk constraint conflicts with the Fields table. You then try altering the Fields table but still you get FK conflicts, due to :-
If an "ALTER TABLE ... RENAME TO" command is used to rename a table that is the parent table of one or more foreign key constraints, the definitions of the foreign key constraints are modified to refer to the parent table by its new name. The text of the child CREATE TABLE statement or statements stored in the sqlite_master table are modified to reflect the new parent table name.
SQLite Foreign Key Support - 5. CREATE, ALTER and DROP TABLE commands
Of course, if acccording to your description, you only want to add the column then the ALTER TABLE Screens ADD COLUMN ScreenNumber INTEGER (with default value if wanted) works without the need to rename tables.
This should be an easy one. I need the SQL to insert into a table that has only one column and it is and autoincrement field.
Similar to this post but SQLite (I am new to SQLite).
Inserting rows into a table with one IDENTITY column only
create table ConnectorIDs
(
ID integer primary key AUTOINCREMENT
);
--none of the following work
INSERT INTO ConnectorIDs VALUES(DEFAULT);
INSERT ConnectorIDs DEFAULT VALUES;
Yes this is strange and if you care here is the reason, if you want to tell me a better way. I have several different item tables that all can have many-to-many links between them but sparse. Instead of having n! bridge tables, or one bridge table with a "Type" that I can't guarantee truly maps to the correct table. I will have one ConnectorID table and each item with have a connectorID key. Then I can have one bridge table.
Insert a null value:
INSERT INTO ConnectorIDs VALUES(NULL);
From the docs:
If no ROWID is specified on the insert, or if the specified ROWID has a value of NULL, then an appropriate ROWID is created automatically.
I only use primary key integer ID for it's "auto-increment function".
What if I don't need an "auto-increment"? Do I still need primary key if I don't care the uniqueness of record?
Example: Lets compare this table:
create table if not exists `table1`
(
name text primary key,
tel text,
address text
);
with this:
create table if not exists `table2`
(
name text,
tel text,
address text
);
table1 applies primary key and table2 don't. Is there any bad thing happen to table2?
I don't need the record to be unique.
SQLite is a relational database system. So it's all about relations. You build relations between tables on keys.
You can have tables without a primary key; it is not necessary for a table to have a primary key. But you will almost always want a primary key to show what makes a record unique in that table and to build relations.
In your example, what would it mean to have two identical records? They would mean the same person, no? Then how would you count how many persons named Anna are in the database? If you count five, how many of them are unique, how many are mere duplicates? Such queries can be done properly, but get overly complicated because of the lacking primary key. And how would you build relations, say the cars a person drives? You would have a car table and then how to link it to the persons table in your example?
There are cases when you want a table without a primary key. These are usually log tables and the like. They are rare. Whenever you are creating a table without a primary key, ask yourself why this is the case. Maybe you are about to build something messy ;-)
You get auto-incrementing primary keys only when a column is declared as INTEGER PRIMARY KEY; other data types result in plain primary keys.
You are not required to declare a PRIMARY KEY.
But even if you do not do this, there will be some column(s) used to identify and look up records.
The PRIMARY KEY declaration helps to document this, enforces uniqueness, and optimizes lookups through the implicit index.
I have table that has a TEXT primary key
CREATE TABLE tbl1{
a1 TEXT PRIMARY KEY,
...
);
(the a1 column is a foreign key inside another table)
How can I change values of a1?
If I do
UPDATE tbl1 SET a1 = ? WHERE a1 = ?
I get a constrain violation error
You should never change primary keys; it would be a better idea to use an INTEGER PRIMARY KEY and have the actual URL be a normal data column.
If you really want change a key that is the target of a foreign key, you should declare the foreign key constraint as deferred so that you are able to adjust the foreign key value in the same transaction.
The problem is that your table has single column that is the primary key and is a foreign key to another table. This suggests that the database design of the database is wrong.
Unless you can change the database structure you need to add the correct values in that other table to change your primary key value.
That is "insert into table constraintingTable(key,val) values (A,B)" and then execute update tbl set a1 = A where a1 = KEY.
Ignore the people telling you that primary keys should never be changed, there is a body of theory on how primary keys should be built. A primary key should uniquely identify the value columns of a row (see database theory), for instance typical keys are PNR, SSN, Serial Number, Mobile Phone number, and sometimes multi values like Name, Address, Street, Country. Generated keys should only be used if you generate new values or you have practical problems using a proper primary key.
I have a sqlite table that was originally created with:
PRIMARY KEY (`column`);
I now need to remove that primary key and create a new one. Creating a new one is easy, but removing the original seems to be the hard part. If I do
.indices tablename
I don't get the primary key. Some programs show the primary key as
Indexes: 1
[] PRIMARY
The index name is typically in the [].
Any ideas?
You can't.
PRAGMA INDEX_LIST('MyTable');
will give you a list of indices. This will include the automatically generated index for the primary key which will be called something like 'sqlite_autoindex_MyTable_1'.
But unfortunately you cannot drop this index...
sqlite> drop index sqlite_autoindex_MyTable_1;
SQL error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
All you can do is re-create the table without the primary key.
I the database glossary; a primary-key is a type of index where the index order is typically results in the physical ordering of the raw database records. That said any database engine that allows the primary key to be changed is likely reordering the database... so most do not and the operation is up to the programmer to create a script to rename the table and create a new one. So if you want to change the PK there is no magic SQL.
select * from sqlite_master;
table|x|x|2|CREATE TABLE x (a text, b text, primary key (`a`))
index|sqlite_autoindex_x_1|x|3|
You'll see that the second row returned from my quick hack has the index name in the second column, and the table name in the third. Try seeing if that name is anything useful.