I am trying to create a database using python to execute the SQL commands (for CS50x problem set 7).
I have created a table with an id field set to AUTO_INCREMENT, but the field in the database is populated only by NULL values. I just want it to have an incrementing id starting at 1.
I've tried searching online to see if I'm using the right syntax and can't find anything obvious, nor can I find someone else with a similar problem, so any help would be much appreciated.
Here is the SQL command I am running:
# For creating the table
db.execute("""
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
middle_name VARCHAR(255) DEFAULT (NULL),
last_name VARCHAR(255) NOT NULL,
house VARCHAR(10),
birth INTEGER
);
""")
# An example insert statement
db.execute("""
INSERT INTO students (
first_name,
middle_name,
last_name,
house,
birth
)
VALUES (
?, ?, ?, ?, ?
);
""", "Harry", "James", "Potter", "Gryffindor", 1980)
Here is a screenshot of the database schema shown in phpliteadmin :
And here is a screenshot of the resulting database:
My guess is that you are using SQLite with phpliteadmin and not MySql, in which case this:
id INTEGER AUTO_INCREMENT PRIMARY KEY
is not the correct definition of the auto increment primary key.
In fact, the data type of this column is set to INTEGER AUTO_INCREMENT, as you can see in phpliteadmin, which according to 3.1. Determination Of Column Affinity, has INTEGER affinity.
Nevertheless it is the PRIMARY KEY of the table but this allows NULL values.
The correct syntax to have an integer primary key is this:
id INTEGER PRIMARY KEY AUTOINCREMENT
This cannot happen, if your statements are executed correctly.
I notice that you are not checking for errors in your code. You should be doing that!
My guess is that the table is already created without the auto_increment attribute. The create table is generating an error and you are inserting into the older version.
You can fix this by dropping the table before you create it. You should also modify the code to check for errors.
Related
I'm basically building a secured online diary application with Flask. However my Python source code returns a syntax error when I try to test the app. I can't detect what's wrong with the syntax. Your help will be appreciated.
I'm attaching a screenshot of the error. And here's my SQL database's schema:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT NOT NULL,
hash TEXT NOT NULL
);
CREATE TABLE sqlite_sequence(name,seq);
CREATE UNIQUE INDEX username ON users (username);
CREATE TABLE diaries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
name TEXT NOT NULL,
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
description TEXT NOT NULL,
img_url TEXT,
FOREIGN KEY(user_id) REFERENCES users(id)
);
New error: unsupported value
It is INSERT statement that causes error.
Well, not the insert itself but the way you're using it.
Values should be passed as a tuple (values between "(" and ")")
So, you need to update db.execute line with something like that
db.execute("insert into table_name(col1, col2) values(?, ?)", (col1_val, col2_val))
UPD. regarding the error on second screenshot.
db.execute("Select...) does not return a value but a set of values.
So, you might wanted to use fetchone() as in docs
res = cur.execute('SELECT count(rowid) FROM stocks') # gets you set records
print(res.fetchone()) # get first record
Anyway, check the docs I provided you link to with.
I run into a problem w. selecting from a encrypted column from a table using psycopg2.
After having created a testtable using
create table users (
id BIGSERIAL NOT NULL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
secret_val_1 BYTEA,
secret_val_2 BYTEA
);
I was able to insert encrypted values into it.
Now I am trying to query values from the table using psycopg2 with:
cur.execute("""
SELECT PGP_SYM_DECRYPT(%s::BYTEA, 'compress-algo=1, cipher-algo=aes256')
FROM users;
""",
('secret_val_1',))
Now this raises an error:
ExternalRoutineInvocationException: Wrong key or corrupt data
Interestingly, when passing the values like so, it works:
def query_users_decrypt(col):
cur.execute("""
SELECT PGP_SYM_DECRYPT({}::BYTEA, 'compress-algo=1, cipher-
algo=aes256') FROM users;
""".format(col),
(col,))
But this is not secure for sql-injection attacks right?
Does anyone know how how to do this right? Thanks!
The format() works because when you pass the secret_val_1 in, it ends up looking like:
SELECT PGP_SYM_DECRYPT(secret_val_1::BYTEA, 'compress-algo=1, cipher-algo=aes256')
FROM users;
What you are looking for is just the straight query:
select pgp_sym_decrypt(secret_val_1, 'compress-algo=1, cipher-algo=aes256')
from users;
The parameter binding is meant for when you want to pass in a value to be used by your query. The secret_val_1 is not a value as it is the name of a column.
Use parameter binding for something like this:
cur.execute("""select pgp_sym_decrypt(secret_val_1, 'compress-algo=1, cipher-algo=aes256'
from users
where username = %s""", ('joeuser',))
how to block the possibility of adding the same values to the database, for example e-mail addresses in python and MySQL?
From database perspective, you would typically put a unique constraint on the corresponding table column:
create table users (
id int auto_increment primary key,
name varchar(50) not null,
email varchar(100) not null unique
);
With this set up in place, any query that would attempt generating a duplicate email (either from an INSERT or an UPDATE) would fail with a unique contraint violation error.
I am using a python code to create MySQL tables.
I am fine to create table using a specific name for my columns, but as soon as I want to change them, the tables are not created anymore.
This code bellow works without any problems
DROP TABLE IF EXISTS sector_tb;
CREATE TABLE sector_tb (
id INT NOT NULL AUTO_INCREMENT,
sector VARCHAR(255) NOT NULL DEFAULT '',
district_id INT NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX sector (sector)
)
COLLATE='latin1_swedish_ci'
;
As soon as I decide to change the name of 'sector' to 'sector1' or anything else, MySQL does not create the table anymore. The code below does not create the table anymore.
CREATE TABLE sector_tb (
id INT NOT NULL AUTO_INCREMENT,
sector1 VARCHAR(255) NOT NULL DEFAULT '',
district_id INT NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX sector (sector)
)
COLLATE='latin1_swedish_ci'
;
There are no errors shown while running the code.
There is an obvious error in second statement:
column name in the index doesn't match column name in the table.
sector1 VARCHAR(255)
UNIQUE INDEX sector (sector)
If your Python code does not report any errors, you must improve error handling.
Two options - drop the original sector_tb and run your second script or rename your column using the alter table command.
I am using sqlite with python 2.5. I get a sqlite error with the syntax below. I looked around and saw AUTOINCREMENT on this page http://www.sqlite.org/syntaxdiagrams.html#column-constraint but that did not work either. Without AUTO_INCREMENT my table can be created.
An error occurred: near "AUTO_INCREMENT": syntax error
CREATE TABLE fileInfo
(
fileId int NOT NULL AUTO_INCREMENT,
name varchar(255),
status int NOT NULL,
PRIMARY KEY (fileId)
);
This is addressed in the SQLite FAQ. Question #1.
Which states:
How do I create an AUTOINCREMENT
field?
Short answer: A column declared
INTEGER PRIMARY KEY will
autoincrement.
Here is the long answer: If you
declare a column of a table to be
INTEGER PRIMARY KEY, then whenever you
insert a NULL into that column of the
table, the NULL is automatically
converted into an integer which is one
greater than the largest value of that
column over all other rows in the
table, or 1 if the table is empty. (If
the largest possible integer key,
9223372036854775807, then an unused
key value is chosen at random.) For
example, suppose you have a table like
this:
CREATE TABLE t1( a INTEGER PRIMARY
KEY, b INTEGER ); With this table,
the statement
INSERT INTO t1 VALUES(NULL,123); is
logically equivalent to saying:
INSERT INTO t1 VALUES((SELECT max(a)
FROM t1)+1,123); There is a function
named sqlite3_last_insert_rowid()
which will return the integer key for
the most recent insert operation.
Note that the integer key is one
greater than the largest key that was
in the table just prior to the insert.
The new key will be unique over all
keys currently in the table, but it
might overlap with keys that have been
previously deleted from the table. To
create keys that are unique over the
lifetime of the table, add the
AUTOINCREMENT keyword to the INTEGER
PRIMARY KEY declaration. Then the key
chosen will be one more than than the
largest key that has ever existed in
that table. If the largest possible
key has previously existed in that
table, then the INSERT will fail with
an SQLITE_FULL error code.
It looks like AUTO_INCREMENT should be AUTOINCREMENT see http://www.sqlite.org/syntaxdiagrams.html#column-constraint
You could try
CREATE TABLE fileInfo
(
fileid INTEGER PRIMARY KEY AUTOINCREMENT,
name STRING,
status INTEGER NOT NULL
);
We just changed the order from
NOT NULL, AUTO_INCREMENT
to
AUTO_INCREMENT NOT NULL,
an example :
cursor.execute("CREATE TABLE users(\
user_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\
user_name VARCHAR(100) NOT NULL)")