I'm currently tryign to learn how to use SQLite3 and am trying to seperate setting up the DB through functions. My second function is where I'm having the error : AttributeError: 'NoneType' object has no attribute 'cursor'. After looking at the SQLite3 doucmentation, I got the impression that it's best to seperate diffrent methods for the DB into diffrent functions.
import sqlite3
from sqlite3 import Error
def create_connection(CRM):
"""
This Function will check to see if the Database is already created, if not will be created.
:param CRM: Location of the Database
:return: None
"""
db = None
try:
db = sqlite3.connect(CRM)
print(sqlite3.version)
except Error as e:
print(e)
finally:
if db:
db.close()
return db
def create_table(db):
cur = db.cursor()
G8Personnel = ''' CREATE TABLE [IF NOT EXISTS] G8Personnel(
DoD INTEGER NOT NULL PRIMARY KEY,
Rank varchar NOT NULL,
FirstName varchar NOT NULL,
LastName varchar NOT NULL,
Role varchar NOT NULL
)'''
cur.execute(G8Personnel)
Company = '''CREATE TABLE [IF NOT EXISTS] Company(
CompanyName varchar PRIMARY KEY,
)'''
cur.execute(Company)
Employee = '''CREATE TABLE [IF NOT EXISTS] Employee(
AutoID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName varchar NOT NULL,
LastName varchar NOT NULL,
Email varchar NOT NULL,
JobTitle varchar,
WebPage varchar,
Notes varchar,
Company varchar
FOREIGN KEY (Company) REFERENCES Company(CompanyName)
)'''
cur.execute(Employee)
Meeting = '''CREATE TABLE [IF NOT EXISTS] Meeting(
AutoID INTEGER PRIMARY KEY AUTOINCREMENT,
Date1 real NOT NULL,
DoD INTEGER NOT NULL,
Employee INTEGER NOT NULL,
MeetingNotes varchar NOT NULL
FOREIGN KEY (DoD) REFERENCES G8Personnel (DoD)
FOREIGN KEY (Employee) REFERENCES Employee (AutoID)
)'''
cur.execute(Meeting)
if __name__ == '__main__':
db = None
create_connection(r'C:\Users\c94re\Documents\Git-Repo\CRM\CRM.db')
create_table(db)
You are not capturing the return value of create_connection. Try to assign the return type to a variable and try again.
if __name__ == '__main__':
db = create_connection(r'C:\Users\c94re\Documents\Git-Repo\CRM\CRM.db')
create_table(db)
I think this should do it, if you have other problems, please edit your question.
Related
This question already has an answer here:
Unfindable SQLite Syntax Error
(1 answer)
Closed 9 months ago.
error: cursor.execute(
sqlite3.OperationalError: near "Order": syntax error
import sqlite3
conn = sqlite3.connect("Cookie.DB")
print("The Employee database is created!")
cursor = conn.cursor()
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS Customer(
customerID TXT PRIMARY KEY NOT NULL,
customerFirstName TEXT NOT NULL,
customerLastName TXT NOT NULL,
address TXT NOT NULL,
email TXT NOT NULL,
Phone TXT NOT NULL,
creditCardInfo TXT NOT NULL
)
CREATE TABLE IF NOT EXISTS Order(
orderID TXT PRIMARY KEY NOT NULL,
FOREIGN KEY (customerID)
REFERENCES Customer (customerID),
customerName TXT NOT NULL,
FOREIGN KEY (cartID)
REFERENCES ShoppingCart (cartID),
orderPrice float NOT NULL,
dateCreated date NOT NULL,
dateShipped date NOT NULL
)
CREATE TABLE IF NOT EXISTS Cookies(
CookieID TXT PRIMARY KEY NOT NULL,
cookieName TXT NOT NULL,
unitCost float NOT NULL,
soldOutOrNot bool NOT NULL
)
CREATE TABLE IF NOT EXISTS ShoppingCart(
CartID TXT PRIMARY KEY NOT NULL,
FOREIGN KEY (customerID)
REFERENCES Customer (customerID),
FOREIGN KEY (cookieID)
REFERENCES Cookies (cookieID),
quantity INT NOT NULL,
dateAdded date NOT NULL,
soldOutOrNot bool NOT NULL
)
"""
)
conn.commit()
print("The employee table is created!")
I see the syntax you are using is wrong as far as I am able to understand try running individual queries like
import sqlite3
conn = sqlite3.connect("mydatabase.db")
cursor = conn.cursor()
# run for each table...
cursor.execute("""CREATE TABLE albums
(title text, artist text, release_date text,
publisher text, media_type text)""")
import sqlite3
# Constructing the database
def create_database():
#Create a database or connect to a database
conn = sqlite3.connect('games_database.db')
conn.execute("PRAGMA foreign_keys = 1") #Turns ON foreign key constraints
#Create cursor
c = conn.cursor()
#Create tables
#Create game_publisher table1
c.execute("""CREATE TABLE IF NOT EXISTS game_publisher(
gp_id INTEGER NOT NULL,
gp_name TEXT NOT NULL,
gp_year_established INTEGER NOT NULL,
PRIMARY KEY(gp_id))
""")
#Create game_genre table2
c.execute("""CREATE TABLE IF NOT EXISTS game_genre(
genre_id INTEGER NOT NULL,
genre_name TEXT NOT NULL,
PRIMARY KEY(genre_id))
""")
#Create platform table3 (Original Platform)
c.execute("""CREATE TABLE IF NOT EXISTS platform(
platform_id INTEGER NOT NULL,
platform_name TEXT NOT NULL,
PRIMARY KEY(platform_id))
""")
#Create games table4
c.execute("""CREATE TABLE IF NOT EXISTS games(
g_id INTEGER NOT NULL,
g_name TEXT NOT NULL,
g_genre INTEGER NOT NULL DEFAULT 0,
g_pub INTEGER NOT NULL DEFAULT 0,
year_released INTEGER NOT NULL,
original_platform INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY(g_id),
FOREIGN KEY(g_genre) REFERENCES game_genre(genre_id) ON DELETE SET DEFAULT ON UPDATE CASCADE,
FOREIGN KEY(g_pub) REFERENCES game_publisher(gp_id) ON DELETE SET DEFAULT ON UPDATE CASCADE,
FOREIGN KEY(original_platform) REFERENCES platform(platform_id) ON DELETE SET DEFAULT ON UPDATE CASCADE)
""")
#Commit changes
conn.commit()
#Close connection
conn.close()
I've tried looking up online and found that SQLite by default has the Foreign key constraint set to OFF.
I found that I had to use this "conn.execute("PRAGMA foreign_keys = 1")" to turn it ON.
When I try to delete a game_publisher, and then view the games table, I don't see the games table update the game_publisher ID to 0.
Do I have to turn ON the foreign key constraint every time I make a connection to the database?
The problem is this:
ON DELETE SET DEFAULT
with the definition of the foreign keys in games, because the default value for all of them is defined to be 0 which (I suspect) does not correspond to a valid id of the corresponding referenced tables.
What you can do is define the foreign keys as nullable and with ON DELETE SET NULL like this:
CREATE TABLE IF NOT EXISTS games (
g_id INTEGER NOT NULL,
g_name TEXT NOT NULL,
g_genre INTEGER, -- nullable
g_pub INTEGER, -- nullable
year_released INTEGER NOT NULL,
original_platform INTEGER, -- nullable
PRIMARY KEY(g_id),
FOREIGN KEY(g_genre) REFERENCES game_genre(genre_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY(g_pub) REFERENCES game_publisher(gp_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY(original_platform) REFERENCES platform(platform_id) ON DELETE SET NULL ON UPDATE CASCADE
)
Now when you delete a row from a parent table, the child key value will be set to NULL, which is allowed.
Finally, for the question:
Do I have to turn ON the foreign key constraint every time I make a
connection to the database?
the answer is yes, if you are going to use operations involving the integerity of the foreign keys, like the insertion of a new row or update a row in the child table games or the modification of rows (deletions or updates) of the parent tables.
Im receiving an error where I am using an incorrect integer value for userID_fk and target. The error comes up for values which have an integer as their data type and if its changed to text or varchar it will state a site has been created and the siteID will increase but no other data will be included. I want the user to input their username so its matched with its userID and inserted into userID_fk through python with Tkinter.
Below is the structure for my users and sites table
users:
CREATE TABLE `users` (
`userID` int(255) NOT NULL AUTO_INCREMENT,
`userName` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
`userPassword` varchar(225) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
`Name` varchar(255) NOT NULL,
`phoneNum` text NOT NULL,
`email` varchar(230) NOT NULL,
`region` text NOT NULL,
`accessLevel` int(10) NOT NULL,
PRIMARY KEY (`userID`)
) ENGINE=InnoDB AUTO_INCREMENT=10002 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
sites:
CREATE TABLE `sites` (
`siteID` int(225) NOT NULL AUTO_INCREMENT,
`siteName` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
`userID_fk` int(255) NOT NULL,
`region` text NOT NULL,
`risklevel` text NOT NULL,
`siteType` text NOT NULL,
`target` int(225) NOT NULL,
PRIMARY KEY (`siteID`),
KEY `userID_fk` (`userID_fk`),
CONSTRAINT `sites_ibfk_1` FOREIGN KEY (`userID_fk`) REFERENCES `users` (`userID`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
Python code to insert a site into the sites table:
def register_site():
sitename_info = sitename2.get()
username2_info = username2.get()
region_info = region.get()
risklevel_info = risklevel.get()
sitetype_info = sitetype.get()
targetpercent_info = targetpercent.get()
# Sql code for writing the data that was written in the regsitering page.
cursor = cnn.cursor()
sitequery = "INSERT INTO `sites`(`siteID`, `siteName`, `userID_fk`, `region`, `risklevel`, `siteType`, `target`) VALUES (NULL,%s,%s,%s,%s,%s,%s)"
sitequery_vals = (sitename_info, username2_info, region_info, risklevel_info, sitetype_info, targetpercent_info)
cursor.execute(sitequery, sitequery_vals)
cnn.commit()
cursor.close()
cnn.close()
# removes the values in the entrys once the user selects that the registration was successful
sitename2_entry.delete(0, END)
region_entry.delete(0, END)
risklevel_entry.delete(0, END)
sitetype_entry.delete(0, END)
targetpercent_entry.delete(0, END)
Label(screen10, text = "Site Created", fg = "green", font = ("calibri", 11)).pack()
If username2_info is the userName, you need to get the userID from the users table:
sitequery = ("INSERT INTO `sites` (`siteName`, `userID_fk`, `region`, `risklevel`, `siteType`, `target`) "
"SELECT %s, `userID`, %s, %s, %s, %s FROM `users` WHERE `userName` = %s")
sitequery_vals = (sitename_info, region_info, risklevel_info, sitetype_info, targetpercent_info, username2_info)
cursor.execute(sitequery, sitequery_vals)
cnn.commit()
I am importing a csv file containing a parent/child (category-subcategory) hierarchy to MySQL, using Python's MySQLdb module. Here is an example csv file:
vendor,category,subcategory,product_name,product_model,product_price
First vendor,category1,subcategory1,product1,model1,100
First vendor,category1,subcategory2,product2,model2,110
First vendor,category2,subcategory3,product3,model3,130
First vendor,category2,subcategory4,product5,model7,190
In MySQL I want to use a category table with a hierarchical structure, like this:
CREATE TABLE IF NOT EXISTS `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL DEFAULT '0',
`status` tinyint(1) NOT NULL,
PRIMARY KEY (`category_id`),
KEY `parent_id` (`parent_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
My question is: How do I determine the parent_id in this table?
Here is the Python script I have so far:
import MySQLdb
import csv
con = MySQLdb.connect('localhost', 'root', '', 'testdb', use_unicode=True, charset='utf8')
with con:
cur = con.cursor()
csv_data = csv.reader(file('test.csv'))
csv_data.next()
for row in csv_data:
cur.execute("SELECT manufacturer_id FROM manufacturer WHERE name=%s", [row[0]],)
res = cur.fetchall()
if res:
vendor_id = res[0][0]
else:
cur.execute("INSERT INTO manufacturer (name) VALUES (%s)", (row[0],))
vendor_id = cur.lastrowid
cur.execute("SELECT category_id FROM category_description WHERE name=%s", [row[2]])
res = cur.fetchall()
if res:
category_id = res[0][0]
else:
# What parent_id should be inserted here?
cur.execute("INSERT INTO category (`status`, `parent_id`) VALUES (%s,%s)", (1,))
category_id = cur.lastrowid
cur.execute("INSERT INTO category_description (category_id, name) VALUES (%s,%s)", (category_id,row[2],))
cur.execute("INSERT INTO product (model, manufacturer_id, price,) VALUES (%s, %s, %s)", (row[4], `vendor_id`, row[8],))
product_id = cur.lastrowid
cur.execute("INSERT INTO product_to_category (product_id, category_id) VALUES (%s, %s)", (product_id, category_id,))
cur.commit()
Here are the definitions of the other tables used in my example:
CREATE TABLE IF NOT EXISTS `manufacturer` (
`manufacturer_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`manufacturer_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `category_description` (
`category_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`category_id`,`language_id`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`model` varchar(64) NOT NULL,
`manufacturer_id` int(11) NOT NULL,
`price` decimal(15,4) NOT NULL DEFAULT '0.0000',
PRIMARY KEY (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `product_to_category` (
`product_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
PRIMARY KEY (`product_id`,`category_id`),
KEY `category_id` (`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
In a hierarchical table structure, any member at the top of its hierarchy has no parents. I would probably show this with a NULL parent ID but based on the way you've defined your category table, it looks like you want to show this by giving the value 0 for the parent ID.
Since you have fixed-depth hierarchies with only two levels (category and subcategory), the task is relatively simple. For each row of the CSV data, you need to:
Check whether the parent (row[1]) is in the table; if not, insert it with a parent ID of 0.
Get the category_id of the parent from step 1.
Check whether the child (row[2]) is in the table; if not, insert it with a parent ID equal to the category_id from step 2.
In your example code, you never access the parent (row[1]); you need to insert this into the table for it to have an ID that the child can refer to. If you've already inserted the parents before this point, you should probably still check to make sure it's there.
You have some other problems here:
The PK of your category_description table is defined on a column that you forgot to define in the table (language_id).
You should really be using InnoDB in this physical model so that you can enforce foreign key constraints in category_description, product and product_to_category.
In your example, cur.commit() is going to throw an exception – that's a method of the Connection object in MySQLdb. Of course, COMMIT isn't implemented for MyISAM tables anyway, so you could also avoid the exception by removing the line entirely.
Referencing row[8] is also going to throw an exception, according to the CSV data you've shown us. (This is a good example of why you should test your MCVE to make sure it works!)
If you do switch to InnoDB – and you probably should – you can use with con as cur: to get a cursor that commits itself when you exit the with block. This saves a couple lines of code and lets you manage transactions without micromanaging the connection object.
I'm trying to create a database with several tables connecting to each other using foreign keys using sqlite3, and I'm writing in python.
Here is my code:
db = sqlite3.connect("PHLC.db")
cur = db.cursor()
# ############################
# delete original table if exist
# drop from the end (foreign key issue)
cur.execute("drop table if exists measurement")
cur.execute("drop table if exists mouse")
cur.execute("drop table if exists drug")
cur.execute("drop table if exists batch")
cur.execute("drop table if exists phlc")
# ############################
# create table
# ############################
# 1. phlc
cur.execute(
"""
CREATE TABLE phlc (
phlc_id INTEGER NOT NULL PRIMARY KEY,
cancer VARCHAR(30) NOT NULL,
histology VARCHAR(60) NOT NULL
)
"""
)
# 2. batch
cur.execute(
"""
CREATE TABLE batch (
batch_id INTEGER PRIMARY KEY AUTOINCREMENT,
phlc_id INTEGER NOT NULL,
FOREIGN KEY (phlc_id) REFERENCES phlc (phlc_id),
batch_number INTEGER NOT NULL
)
"""
)
# 3. drug
cur.execute(
"""
CREATE TABLE drug (
drug_id INTEGER PRIMARY KEY AUTOINCREMENT,
drug_name VARCHAR(30) NOT NULL,
batch_id INTEGER NOT NULL,
FOREIGN KEY (batch_id) REFERENCES batch (batch_id)
)
"""
)
# 4. mouse
cur.execute(
"""
CREATE TABLE mouse (
mouse_id INTEGER PRIMARY KEY AUTOINCREMENT,
drug_id INTEGER NOT NULL,
FOREIGN KEY (drug_id) REFERENCES drug (drug_id)
)
"""
)
# 5. measurement
cur.execute(
"""
CREATE TABLE measurement (
measurement_index INTEGER PRIMARY KEY AUTOINCREMENT,
mouse_id INTEGER NOT NULL,
FOREIGN KEY (mouse_id) REFERENCES mouse (mouse_id),
day INTEGER NOT NULL,
tumor_volume FLOAT NOT NULL,
comment VARCHAR(255) NULL
)
"""
)
db.commit()
db.close()
The error I'm getting is at the batch table:
sqlite3.OperationalError: near "batch_number": syntax error
Can someone point out the problem with the code? (It worked fine with MySQL..)
According to the documentation, any table constraints must come after all column definitions:
CREATE TABLE batch (
batch_id INTEGER PRIMARY KEY AUTOINCREMENT,
phlc_id INTEGER NOT NULL,
batch_number INTEGER NOT NULL,
FOREIGN KEY (phlc_id) REFERENCES phlc (phlc_id)
)
Alternatively, make the foreign key declaration a column constraint:
CREATE TABLE batch (
batch_id INTEGER PRIMARY KEY AUTOINCREMENT,
phlc_id INTEGER NOT NULL REFERENCES phlc (phlc_id),
batch_number INTEGER NOT NULL
)