I am using sqlLite Studio to create a sql lite database however the ddl it is producing is giving an error I want my primary key to be auto number here is the code and the options i selected
PRAGMA foreign_keys = 0;
CREATE TABLE sqlitestudio_temp_table AS SELECT *
FROM ExportProcessed;
DROP TABLE ExportProcessed;
CREATE TABLE ExportProcessed (ID INTEGER PRIMARY KEY, ORDERID INTEGER, PROCESSED BOOLEAN, ProcessedBy STRING, PRIMARY KEY (ID DESC) AUTOINCREMENT);
INSERT INTO ExportProcessed (
ID,
ORDERID,
PROCESSED,
ProcessedBy
)
SELECT ID,
ORDERID,
PROCESSED,
ProcessedBy
FROM sqlitestudio_temp_table;
DROP TABLE sqlitestudio_temp_table;
PRAGMA foreign_keys = 1;
Here is the auto increment
This is the errror message I am getting
This is the version of sql lite studio I am using.
You are trying to create 2 primary indexes. However, AUTOINCREMENT is highlighted as the error (as AUTOINCREMENT can only be specified for a PRIMARY INDEX, which has already been created internally/theorectically, so cannot now be coded).
Removing AUTOINCREMENT results in table "ExportProcessed" has more than one primary key.
The fix could be to use :-
CREATE TABLE ExportProcessed (ID INTEGER, ORDERID INTEGER, PROCESSED BOOLEAN, ProcessedBy STRING, PRIMARY KEY(ID DESC AUTOINCREMENT));
Additional Consideration
Do you really need or even want AUTOINCREMENT? All that AUTOINCREMENT does is specify that a different algorithm is used when determining the underlying rowid and that the generated rowid is greater than the largest used rowid.
Not coding AUTOINCREMENT, but still defining INTEGER PRIMARY KEY still results in an automatically generated rowid (which will typically be larger until/if the number of the largest rowid of 9223372036854775807 has been used, after which using AUTOINCREMENT will fail with an SQLITE_FULL error, however without an attempt will be made to utilise a free/unused lower value if available).
Using ID INTEGER PRIMARY KEY or ID INTEGER,..., PRIMARY KEY(ID) with or without AUTOINCREMENT makes the column ID an alias of the rowid (not normally seen column).
Using AUTOINCREMENT has overheads and is not recommended as per :-
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and
disk I/O overhead and should be avoided if not strictly needed. It is
usually not needed.
SQLite Autoincrement
AUTOINCREMENT v not coding it Example
Consider the following :-
DROP TABLE IF EXISTS ExportProcessedV2;
CREATE TABLE IF NOT EXISTS ExportProcessedV2 (ID INTEGER, ORDERID INTEGER, PROCESSED BOOLEAN, ProcessedBy STRING, PRIMARY KEY(ID DESC));
INSERT INTO ExportProcessedV2 (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
INSERT INTO ExportProcessedV2 (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
INSERT INTO ExportProcessedV2 VALUES(9223372036854775807,100,0,null); -- insert with the highest possible rowid
INSERT INTO ExportProcessedV2 (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
SELECT * FROM ExportProcessedV2;
DROP TABLE IF EXISTS ExportProcessed;
CREATE TABLE IF NOT EXISTS ExportProcessed (ID INTEGER, ORDERID INTEGER, PROCESSED BOOLEAN, ProcessedBy STRING, PRIMARY KEY(ID DESC AUTOINCREMENT));
INSERT INTO ExportProcessed (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
INSERT INTO ExportProcessed (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
INSERT INTO ExportProcessed VALUES(9223372036854775807,100,0,null); -- insert with the highest possible rowid
INSERT INTO ExportProcessed (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null);
SELECT * FROM ExportProcessed;
The former (V2) without AUTOINCREMENT works and results in :-
i.e. after reaching the highest possible rowid a lower free/unused rowid has been used.
However, the latter using AUTOINCREMENT fails as per :-
INSERT INTO ExportProcessed (ORDERID,PROCESSED, PROCESSEDBY) VALUES (100,0,null)
> database or disk is full
and if the inserts or not within a transaction will result in a table :-
Additional re SQLite Studio
After installing SQLite Studio and checking a few scenarios the following issues have been found.
1. Multiple PRIMARY KEYS can be defined per table when only 1 should e.g. :-
The generated DDL being (which can't be committed) :-
CREATE TABLE EPV1 (ID INTEGER PRIMARY KEY DESC AUTOINCREMENT, PRIMARY KEY (ID DESC) AUTOINCREMENT, PRIMARY KEY (ID ASC), PRIMARY KEY (ID DESC) AUTOINCREMENT);
**2. An SQLite Bug with INTEGER PRIMARY KEY DESC is not handled correctly.
SQLite has a bug as per
if the declaration of a column with declared type "INTEGER" includes
an "PRIMARY KEY DESC" clause, it does not become an alias for the
rowid and is not classified as an integer primary key. This quirk is
not by design. It is due to a bug in early versions of SQLite. But
fixing the bug could result in backwards incompatibilities. Hence, the
original behavior has been retained (and documented) because odd
behavior in a corner case is far better than a compatibility break.
This means that the following three table declarations all cause the
column "x" to be an alias for the rowid (an integer primary key):
SQLite Studio if configuring with AUTOINCREMENT and sort DESC creates DDL as
CREATE TABLE EPV1 (
ID INTEGER PRIMARY KEY DESC AUTOINCREMENT
);
Dues to the above ID is not an alias for the rowid and thus cannot have AUTOINCREMENT coded. The correct DDL should be the subtly different :-
CREATE TABLE IF NOT EXISTS EPV1 (
ID INTEGER, PRIMARY KEY (ID DESC AUTOINCREMENT)
);
Related
I use the MS Sync Framework to sync my SQL Server instance with a local SQL CE file to make it possible working offline with my Windows app.
I use GUIDs as keys. On my table I have a unique index on 2 columns: user_id and setting_id:
usersettings table
------------------
id PK -> I also tried it without this column. Same result
user_id FK
setting_id FK
value
Now I do the following:
I create a new record in this table in both databases - SQL Server and SQL CE with the same user_id and setting_id.
This should work and merge the data together since this can happen in real life. But I get an error when syncing saying the unique key constraint led to an error. The key pair already exists in the table.
A duplicate value cannot be inserted into a unique index. [ Table name = user_settings,Constraint name = unique_userid_settingid ]
Why can't MS sync handle that? It should not try to insert the key pair again. It should update the value if needed.
The issue is if you add the same key pair to different copies of the table, they get different IDs (GUIDs) as primary keys in this usersettings table.
As this is simply a many-to-many table between Users and Settings, there is no need to have that ID as a PK (or even a column at all).
Instead, just use a concatenated key of the two FKs e.g.,
CREATE TABLE [dbo].[usersettings](
[user_id] [UNIQUEIDENTIFIER] NOT NULL,
[setting_id] [UNIQUEIDENTIFIER] NOT NULL,
[value] [varchar](50) NOT NULL,
CONSTRAINT [PK_usersettings] PRIMARY KEY CLUSTERED ([user_id] ASC, [setting_id] ASC) );
Of course, include appropriate field settings (e.g., if you use VARCHARs to store the IDs) and relevant FKs.
As the rows inserted should now be identical on the two copies, it should merge fine.
If you must have a single column as a unique identifier for the table, you could make it meaningful e.g.,
the PK (ID) becomes a varchar (72)
it gets filled with CONCAT(user_ID, setting_id)
As the User_ID and Setting_ID are FKs, you should already have them generated so concatenating them should be easy enough.
Do you get the error during sync, then it should appear as a conflict, that you must solve in code.
https://learn.microsoft.com/en-us/previous-versions/sql/synchronization/sync-framework-2.0/bb734542(v=sql.105)
I also see this in the manual: By default, the following objects are not copied to the client database: FOREIGN KEY constraints, UNIQUE constraints, DEFAULT constraints, and the SQL Server ROWGUIDCOL property. This indicates poor support for your scenario
I suggest you remove the unique constraint from the device table.
I have a ward table and it contains columns like wardid, wmemname, isActive, and so on... wardid is the primary key and isActive is boolean.
If the user deletes the record from the front end, I set isActive to false.
"Record is deleted successfully"
This message is shown to the user.
In my delete procedure I wrote an update statement to make isActive set to false:
update wardtable
set isActive = false
where wardid = #wardid
Fine up to here. In case the user wants to enter the details with the deleted wardid, now there is a problem with a primary key violation message from the front end when he tries to enter the data with the deleted wardid.
How to solve this issue?
Suppose if I take another id in my ward table then, it allows if I make id as an autoincrement. But duplicate wardid's are allowed in my ward table if I do like that.
So, what is the best way to do this?
Your doing too much with your primary key.
Create a real primary key of type uniqueidentifier / long and auto generated if need be.
Wardid should NOT be your primary key for this table, use your business logic to lookup data on this column and update / delete / insert as required. leave the new primary key for use by your database only. If wardid needs to be unique, make it a unique column by adding it to a unique index or use business logic.
To add on to uk2k05's answer an example of how you would implment it would be
CREATE TABLE dbo.wardtable
(
wardTableId bigint NOT NULL IDENTITY (1, 1),
wardid int NOT NULL,
deletedUniqueifier uniqueidentifier NOT NULL default('00000000-0000-0000-0000-000000000000'),
wmemname varchar(50) NOT NULL,
isActive AS (case when deletedUniqueifier = '00000000-0000-0000-0000-000000000000' then 1 else 0 end) PERSISTED
)
ALTER TABLE dbo.wardtable ADD CONSTRAINT
PK_wardtable PRIMARY KEY CLUSTERED (wardTableId)
CREATE UNIQUE NONCLUSTERED INDEX UX_wardtable_wardid
ON dbo.wardtable (wardid, deletedUniqueifier)
Now that isActive is a computed column your update would also have to change to
update wardtable
set deletedUniqueifier = newid()
where wardid = #wardid and deletedUniqueifier = '00000000-0000-0000-0000-000000000000'
One other logical change you will need to do, any forgen keys that link to this table should link using wardTableId instead of wardid
I have two tables:
create table `db_csms`.`tbl_item_requester`
(
`id` int not null,
`item_id` int not null,
`requester_id` int not null,
foreign key(`item_id`) references `db_csms`.`tbl_items`(`item_id`),
foreign key(`requester_id`) references `db_csms`.`tbl_user_details`(`user_id`),
primary key (`id`)
);
create table `db_csms`.`tbl_item_requests`
(
`id` int not null,
`item_requester_id` int not null,
`quantity` int(5) not null default 0,
foreign key(`item_requester_id`) references `db_csms`.`tbl_item_requester`(`id`),
primary key (`id`)
);
tbl_items and tbl_user_details are already populated with values. My problem is when a new row is added into table 1 because the table 2 uses the id of that new row inserted in table 1.
My issues are:
How to get the newly inserted row id of table 1 which is needed for inserting in table 2.
Strategy to solve this issue(my thinking):
Remove auto_increment and then generate a random value (using C# code) and use that value in both tables.
Are there any workaround to this problem? Do i have to change my strategy? Is the Database design incorrect?
Since you're using MySQL as your database, there is the specific function LAST_INSERT_ID()
which only works on the current connection that did the insert.
In case of SQL Server you could write:
Insert .... Values(....); Select Scope_Identity()
and use SqlCommand.ExecuteScalar() that returns the first value of the first row, which would be the ID of newly inserted row. In MySql, you should be able to write last_insert_id() instead of Scope_identity().
I want to implement a patients data base for our software, and have an issue with the foreign key statement. I am using the latest SQLite DLLs, with C#.
When I try to run below code:
dbConnection = "Data Source=SQLiteMyDatabase.db;foreign keys=true;";
if (connections == 0)
{
cnn = new SQLiteConnection(dbConnection);
cnn.Open();
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS patients ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR(100) NOT NULL;");
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS images ( FOREIGN KEY (patientID) REFERENCES patients(id), nameRed VARCHAR(20) NOT NULL PRIMARY KEY;");
}
I get the error:
SQLite error near "FOREIGN": syntax error
Why does this happen?
In order to create a foreign key, you must first create the column:
CREATE TABLE IF NOT EXISTS images (
nameRed VARCHAR(20) NOT NULL PRIMARY KEY,
patientID INT,
FOREIGN KEY (patientID) REFERENCES patients(id)
);
Please note:
I moved the primary key column (nameRed) first in the list of columns created, but that's just convention. It could go second.
You use the data type VARCHAR and SQlite will accept that, but be aware that it gets mapped to type TEXT, the maximum length will be ignored, and you will be able to store other data types in the column. SQLite is a bit funny when it comes to data types (it has a very well thought-out system but it's quite different from most other SQL databases).
To make things more confusing, you are allowed to declare the PRIMARY KEY as a property of the column (although you can also do it after the list of columns as with the FOREIGN KEY).
I'm trying (SQL Server Compact) to add primary key constraint on existing table that has some rows in it. While adding primary key I'm getting the error:
"A duplicate key cannot be inserted into a unique index"
I don't what this is, can anyone help me with this?
Make sure the data in the table respects the contraint you're trying to set on the table. If the column you are making primary has duplicate entries, it won't be able to work as primary key, hence the error.
You could try and find the rows with duplicate entries, with something like this:
select Id, Count(*) from myTable
having Count(*) > 1
group by Id
Try this
select id_column, count(*) from your_table group by id_column having count(*) > 1
If there are any records returned from this above query you cannot add a primary key on id_column since duplicate IDs exist.
Of course you will need to replace id_column and your_table with the appropriate names.