Code:
import sqlite3
c = sqlite3.Connection(':memory:')
c.execute('CREATE TABLE foo(a INTEGER, b VARCHAR(8), PRIMARY KEY(a, b))')
c.execute('INSERT INTO foo(a) VALUES (1)')
c.execute('INSERT INTO foo(a) VALUES (1)')
print(c.execute('SELECT * FROM foo').fetchall())
Output:
[(1, None), (1, None)]
Why is SQLite inserting rows with duplicate primary keys? How do I fix this?
SQL PK (PRIMARY KEY) means UNIQUE NOT NULL. You shouldn't expect to be able to have a NULL in a value for a PK, let alone only one. You should declare PK columns NOT NULL and not put NULL in them.
SQL As Understood By SQLite:
Each row in a table with a primary key must have a unique combination of values in its primary key columns. For the purposes of determining the uniqueness of primary key values, NULL values are considered distinct from all other values, including other NULLs. If an INSERT or UPDATE statement attempts to modify the table content so that two or more rows have identical primary key values, that is a constraint violation.
According to the SQL standard, PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a bug in some early versions, this is not the case in SQLite. Unless the column is an INTEGER PRIMARY KEY or the table is a WITHOUT ROWID table or the column is declared NOT NULL, SQLite allows NULL values in a PRIMARY KEY column. SQLite could be fixed to conform to the standard, but doing so might break legacy applications. Hence, it has been decided to merely document the fact that SQLite allowing NULLs in most PRIMARY KEY columns.
Since NULL in a PK is against SQL, it seems moot what SQLite then chooses to do when constraining and manipulating tables with NULLs in a PK. But it uses the usual SQL interpretation that NULL is not equal to NULL for purposes of UNIQUE. This is like when you declare a column set UNIQUE NULL. So as a constraint, SQLite PK is a synonym for UNIQUE instead of UNIQUE NOT NULL.
A UNIQUE constraint is similar to a PRIMARY KEY constraint, except that a single table may have any number of UNIQUE constraints. For each UNIQUE constraint on the table, each row must contain a unique combination of values in the columns identified by the UNIQUE constraint. For the purposes of UNIQUE constraints, NULL values are considered distinct from all other values, including other NULLs.
SQLite, like many other SQL databases, considers two NULLs as different values for the purposes of uniqueness (partially because, in SQL, NULL == NULL is false).
I don't believe there is a way to alter this behavior. As a workaround, you can use an empty string in column b as "no value".
Related
I am trying to build a composite primary key for my tabels. They should also have a self incremented id. My problem is that when I use a composite primary key the ID becomes NULL (as seen in the pictures)
here it works as it should but no composite key
here the id is NULL no matter what.
I tried different synatxes and also key words like NOT NULL and AUTOINCREMENT but nothing seems to work.
Here is the code without composite key
mystr = "CREATE TABLE IF NOT EXISTS KM%s(id INTEGER PRIMARY KEY, date TEXT, client INTEGER)"%(month.replace('-',"))
print(mystr)
c.execute(mystr) #create a table
conn.commit()'''
Here is the code with COMPOSITE KEY
mystr = "CREATE TABLE IF NOT EXISTS KM%s(id INTEGER, date TEXT, client INTEGER, primary key (id, client)"%(month.replace('-',"))
print(mystr)
c.execute(mystr) #create a table
conn.commit()
I was sure that I'd used autoincremented integer columns in the past which were not primary keys, but it certainly doesn't work today with SQLite.
I must echo what #forpas has already said in the comment that you just can't do that.
The solution would be to add the UNIQUE constraint to id and generate your ID programmatically as you go. You do not need to track your current maximum ID because you can simply ask SQLite what the max is:
SELECT MAX(id) FROM KM<month>;
Increment that value by 1 and include it in your INSERT INTO statement.
I'd like to offer a couple of tips:
Using two integers as your composite key is a bad idea. Take composite key 1315 for example. Is that client 315 with an ID of 1, client 15 with an ID of 13, or client 5 with an ID of 131? It's true that primary keys are just for searching and do not have to be unique in many cases, but using integers generally does not work well.
The second tip is not to create a new database table for each month. A very good rule is that identically-structured tables should be combined into a single table. In this case you would add a column called month (actually, it would be 'date' then you would search by month) and keep everything in one table, not one table per month.
I am creating a database from different CSV files. After doing this I have tried to define the primary key table by table but I got an error.
c.execute("ALTER TABLE patient_data ADD PRIMARY KEY (ID);").fetchall()
OperationalError: near "PRIMARY": syntax error
Maybe the best thing to avoid this error is to define the primary key when the table is create but I dont know how to do that. I have been working with python for a few years but today is my first approach with SQL.
This is the code I use to import a CSV to a table
c.execute('''DROP TABLE IF EXISTS patient_data''')
c.execute(''' CREATE TABLE patient_data (ID, NHS_Number,Full_Name,Gender, Birthdate, Ethnicity, Postcode)''')
patients_admitted.to_sql('patient_data', conn, if_exists='append', index = False)
c.execute('''SELECT * FROM patient_data''').fetchall()
This is too long for a comment.
If your table does not have data, just re-create it with the primary key definition.
If your table does have data, you cannot add a primary key in one statement. Why not? The default value is either NULL or constant. And neither is allowed as a primary key.
And finally, SQLite does not allow you to add a primary key to an existing table. The solution is to copy the data to another table, recreate the table with the structure you want, and then copy the data back in.
I know this question was asked before here. The reason was a mismatch between the SQL schema and the inserted data.
So I made sure that the SQL schema matches my inserted data. But I get an IntegrityError Error.
Could you tell me, where the datatype mismatch could be?
conn = sqlite3.connect("contdata_sql.db")
c = conn.cursor() # ich brauche ein Curser Object
c.execute('''CREATE TABLE imbalanced ([ChannelStatusResult] INTEGER PRIMARY KEY,
[Channels] text,
[Channel] text,
[Channel_Type] text,
[Channel_Name] text)''')
np.array(map(str, array_2d_sql))# make sure all values are strings
print("array_2d_sql = ",array_2d_sql)
# = ['ChannelStatusResult' 'Channels' 'Channel' 'ChannelName'
#'REST_RECEIVER_LOOKUP']
# ['ChannelStatusResult' 'Channels' 'Channel' 'ChannelID'
# '87842bb134ba31cf9c43685fabcd2eac']
...
print("array_2d_sql.shape = ",array_2d_sql.shape) # = (461, 5)
c.executemany('''INSERT INTO imbalanced VALUES (?,?,?,?,?)''', array_2d_sql) # Error occures here!!!
Any type of data can be stored in any type of column , with one exception, the exception being that a column defined specifically as INTEGER PRIMARY KEY (with or without AUTOINCREMENT) is an alias of the rowid column, which must be an integer. If it is not an integer then that is when you get the datatype mismatch error.
As such the cause is that the first value of your insert is not an integer.
Typically INTEGER PRIMARY KEY is used for a self-generated unique identifier and the value is not supplied but used as a means of uniquely identifying a row. In such a usage a value is not provided (or null can be used) and SQLite generates a value (1 for the first, then likely 2, then 3 and so on).
The actual best fix is unclear, other than to say that you probably need to define the [ChannelStatusResult] differently, so that it is not INTEGER PRIMARY KEY and therefore that the column is not an alias of the rowid column.
If you used
c.execute('''CREATE TABLE imbalanced ([ChannelStatusResult] INT PRIMARY KEY,
[Channels] text,
[Channel] text,
[Channel_Type] text,
[Channel_Name] text)''')
As INTEGER PRIMARY KEY isn't coded then the [ChannelStatusResult] column is not an alias of the rowid and thus can be any value. The rowid column is then hidden but still usable e.g. you could use SELECT *,rowid FROM any_table.
However, without being aliased, the rowid can be changed by VACUUM and therefore cannot be relied upon to not change (and should therefore not be used for relationships (a common and efficient means of building relationships between tables)).
Note although INT PRIMARY KEY may resolve the issue, this may not be the best fix.
I am trying to do a SQLite insert from my python script.
I am getting an error:
table history has 4 columns but 3 values were supplied
The reason there is 3 not 4, is that the first one is my ID. I assumed that as i declared it as a primary key it would auto-increment the value. How do I go about inserting the ID
.py:
c.execute("INSERT INTO history VALUES (?,?,?)", (q[0],t,in))
.db
CREATE TABLE history (id integer primary key, employeeID integer, time datetime, inout varchar);
You either have to provide values for all columns, or name the columns you are inserting into explicitly. SQLite will not go and guess what columns you provided values for, you need to be explicit about them.
You can use a NULL to have SQLite insert an auto-generated id for you:
c.execute("INSERT INTO history VALUES (NULL,?,?,?)", (q[0],t,in))
or you can name the 3 columns you are inserting into explicitly:
c.execute("INSERT INTO history (employeeID, time, inout) VALUES (?,?,?)", (q[0],t,in))
I'm trying to get a rowid if a data row exists. What I have now is
row_id = self.dbc.cursor.execute("SELECT ROWID FROM Names where unq_id=?",(namesrow['unq_id'],)).fetchall()[0][0]
where namesrow is a dictionary of column names with corresponding data to fill into the table. The problem is this prints 'unq_id' when runs and I'm not sure how to get rid of it.
I'm using sqlite3 and python. Any help's appreciated!
quoting the sqlite documentation:
With one exception noted below, if a rowid table has a primary key
that consists of a single column and the declared type of that column
is "INTEGER" in any mixture of upper and lower case, then the column
becomes an alias for the rowid.
So if your unq_id is the integer primary key in this table, then rowid and unq_id will be the same field.