Working with databases with Python: Course registration data in JSON - python

I am able to get my Python code to run print the desired results, but my problem is with the SQLite table. I was asked to apply this SQL command to the tables:
SELECT hex(User.name || Course.title || Member.role ) AS X
FROM User JOIN Member JOIN Course
ON User.id = Member.user_id AND Member.course_id = Course.id
ORDER BY X
I was able to execute the command in SQLite, but according to the instructions for this project, X is supposed to start with 416 in row one of the results column produced. However, the X I got for row 1 in the results was:
43616C6962736933313030
Here is what I wrote in Python so far:
import sqlite3
import json
#Working with Java and Sqlite
conn = sqlite3.connect('rosterdb.sqlite')
cur = conn.cursor()
cur.executescript('''
DROP TABLE IF EXISTS User;
DROP TABLE IF EXISTS Member;
DROP TABLE IF EXISTS Course;
CREATE TABLE User(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT UNIQUE
);
CREATE TABLE Member(
user_id INTEGER UNIQUE,
course_id INTEGER UNIQUE,
role INTEGER,
PRIMARY KEY (user_id, course_id)
);
CREATE TABLE Course(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
title TEXT UNIQUE
);
''')
#primary key for junction table is composite of both user_id and course_id
fname = raw_input("Enter file name:")
if (len(fname) < 1): fname = 'roster_data.json'
#prompts for file name
str_data = open(fname).read()
json_data = json.loads(str_data)
#opens the file and reads it all
#loads the json data and now is a python list
for entry in json_data:
title = entry[1];
name = entry [0];
role = entry[2];
#["Charley, "sill0", 1] represents the name, course title, and role
print name, title, role
cur.execute('''INSERT or IGNORE INTO User (name)
VALUES (?)''', (name, ))
cur.execute('SELECT id FROM User WHERE name = ?',(name, ))
user_id = cur.fetchone()[0]
cur.execute('''INSERT or IGNORE INTO Course (title)
VALUES (?)''', (title, ))
cur.execute('SELECT id FROM Course WHERE title = ?', (title, ))
course_id = cur.fetchone()[0]
cur.execute('''INSERT or REPLACE INTO Member (user_id, course_id, role)
VALUES (?,?,?)''', (user_id, course_id, role))
#INSERT, SELECT AND FETCHONE STATEMENTS
conn.commit()
Here is the JSON data that I was working with. It is about course registration for students: roster_data.json Here is the link to it:
https://pr4e.dr-chuck.com/tsugi/mod/sql-intro/roster_data.php?PHPSESSID=9addd537cfe55c03585d2bfaa757f6b0
I am not sure if I implemented the "role" key correctly. Thank you for your inputs!

The problem is that you made Member.course_id unique. Thus you can have no more members than courses. Using REPLACE in INSERT or REPLACE into Member hides this error.
Just drop UNIQUE constraint on Member.course and you will get expected result.

Related

Create SQLite Table With Variable

I want to create three tables fremdgehen.com, molligundwillig.de and reifer6.de.
But I am not able to transfer each element to CREATE TABLE. Why?
import sqlite3
con = sqlite3.connect('emails.db')
cur = con.cursor()
pages = ['fremdgehen.com', 'molligundwillig.de', 'reifer6.de']
for i in pages:
try:
sql_command = f'''
CREATE TABLE {i} (
email INTEGER,
password VARCHAR,
PRIMARY KEY (id));
cur.executescript(sql_command)
con.commit()
'''
except:
pass
con.close()
Since the table names contain a . character, you have to escape the names.
sql_command = f'''
CREATE TABLE `{i}` (
email INTEGER,
password VARCHAR,
PRIMARY KEY (id));
cur.executescript(sql_command)
con.commit()
'''
Note that having . in table and column names is inconvenient, because . is the separator between database, table, and column names. So you'll have to escape the table name in all your queries. Consider removing the . before using it as a table name to simplify this.

How to let user input TABLE name in sqlite3, python3?

I need to prompt a user to create a student table, check if a table with such a name exists in the database, and if not create it.
import sqlite3
conn = sqlite3.connect('School')
print ("Database has been created")
def create_table():
TableName = input("Enter table name: ")
tb_create ="""CREATE TABLE , (TableName,) (ID INT PRIMARY KEY,title VARCHAR(10), forename VARCHAR(20),
surname VARCHAR(20))"""
tb_exists ="SELECT name FROM sqlite_master WHERE type='table' AND name= ?", (TableName,)
if not conn.execute(tb_exists).fetchone():
conn.execute(tb_create)
print ("Table created successfully")
else:
print ("Table Exists!")
I know its possible to inser user inputed value into a table, but how do I create a table with inputed name? What should go after CREATE TABLE? If I use , (TableName,) the code wont compile.
Also, once the new table has been added to database, how do I indicate its name in INSER INTO query?
def insert_data():
conn.execute("INSERT INTO TableName (ID,title,forename,surname)VALUES \
(234,'Mr','XXX','XXX'")
conn.commit()
The correct syntax for a CREATE TABLE statement is:
CREATE TABLE tablename(column1 datatype1, column2 datatype2, ....)
Since you want the user to provide the name of the table, you can do it with string interpolation, because you can't pass it with a ? placeholder in the sql query as aparameter:
tb_create = f"CREATE TABLE [{TableName}](ID INTEGER PRIMARY KEY, title TEXT, forename TEXT, surname TEXT)"
The table's name must be enclosed inside square brackets, just in case the user provided a name that is not valid (for example it starts with digit or contains spaces).
Also, if you want the column ID to be autoincrement, you must use INTEGER instead of INT for its data type.
Also, there is no VARCHAR data type in SQLite. Use TEXT.
You can define the variable TableName as global so that you can use it in all the functions, like insert_data().
Use string interpolation for the INSERT statement also.
import sqlite3
conn = sqlite3.connect("School")
print ("Database has been created")
TableName = ""
def create_table():
global TableName
TableName = input("Enter table name: ").strip()
tb_exists ="SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?"
if not conn.execute(tb_exists, (TableName,)).fetchone():
tb_create = f"CREATE TABLE [{TableName}](ID INTEGER PRIMARY KEY, title TEXT, forename TEXT, surname TEXT)"
conn.execute(tb_create)
print("Table created successfully")
else:
print("Table Exists!")
def insert_data():
if len(TableName) > 0:
conn.execute(f"INSERT INTO [{TableName}] (ID,title,forename,surname) VALUES (234,'Mr','XXX','XXX')")
conn.commit()
create_table()
insert_data()
The name of the table, or of the columns cannot be parameterized, so you must build the query string. It means that you should control that the entered name is sane because building query from strings is know to be a vector for SQL injection.
But most (if not all) SQL database allow to create a table if it does not already exists. The syntax is just:
CREATE TABLE table_name IF NOT EXISTS (
column_name type,
...)
So here, you could just do:
import re
...
def create_table():
TableName = input("Enter table name: ")
# control name:
if not re.match(r'\w*$', TableName):
raise IllegalValue("Invalid table name")
tb_create =f"""CREATE TABLE {TableName} IF NOT EXISTS (ID INT PRIMARY KEY,title VARCHAR(10),
forename VARCHAR(20), surname VARCHAR(20))"""
conn.execute(tb_create)

I can't create table by getting column names from a list?(postgresql/psycopg2)

I have prepared two sample lists below. My goal is to create a table with these two lists in postgresql.id will be bigserial primary key.but I keep getting errors. how do you think i can do that?
My example list and code:
my_column_name = ['id','first name','surname','age']
data= [{'Jimmy', 'wallece', 17}]
connection = psycopg2.connect(user = "postgres",
password = "Sabcanuy.1264",
host="127.0.0.1",
port="5432",
database="postgres")
cursor = connection.cursor()
create_table_query = '''CREATE TABLE unit_category_report (ID BIGSERIAL PRIMARY KEY ,
my_columne_name); '''
Strings cannot access variables and their values.
I’m not 100% sure this will work but you can try:
my_column_name =['id','first_name','surname','age']
create_table_query = '''CREATE TABLE unit_category_report (ID BIGSERIAL PRIMARY KEY , %s); ''' % (my_column_name)
Or...
create_table_query = '''CREATE TABLE unit_category_report (ID BIGSERIAL PRIMARY KEY , {0}); '''.format(my_column_name)
You may have to switch to double quotes from the triple single quote.

Creating an sql table based off of a variable

I am creating a database that includes 3 primary tables:
Users, Assignments, Groups
With other potential tables that relate to the table 'Groups'. These potential tables are meant to be tables which are named based on the key variable in the "Groups" table. eg if the Groups table has an entry with groupName = "Group_One", I want to create a table called "Group_One" and then store the usernames of other users into that table. As don't see a practical way to store multiple usernames in one row of the 'Groups' table.
Here is the code I am testing to try and implement this:
import sqlite3
def Database_Setup():
Cur.executescript(
"""
CREATE TABLE IF NOT EXISTS USERS
(
username text,
password text,
clearance int,
classes int
);
CREATE TABLE IF NOT EXISTS GROUPS
(
groupName text
teacher text,
teachingAssistant text
users
);
CREATE TABLE IF NOT EXISTS ASSIGNMENTS
(
assignmentID int,
assignmentName text,
assignmentInfo text,
dueDate date,
setDate date,
completedAmount int
)
"""
)
def Potential_Solution():
Group_Name = "Group1"
List_Of_Users = ["User1","User2","User3"]
Cur.execute("""
CREATE TABLE IF NOT EXISTS {}
(
username text,
randomVar text
)
""".format(Group_Name))
# This part works fine ^^
for User in List_Of_Users:
Cur.execute("INSERT INTO TABLE ? values (?,'Some_Var')",(Group_Name,User))
def Main():
Database_Setup()
Potential_Solution()
Cur.execute("SELECT * FROM Group1")
print(Cur.fetchall())
if __name__ == "__main__":
Conn = sqlite3.connect("FOO_DB.db")
Cur = Conn.cursor()
Main()
However when I execute this, I run into this error:
Traceback (most recent call last):
File "E:/Python/Py_Proj/DB LIST vs new db example.py", line 53, in <module>
Main()
File "E:/Python/Py_Proj/DB LIST vs new db example.py", line 46, in Main
Potential_Solution()
File "E:/Python/Py_Proj/DB LIST vs new db example.py", line 42, in Potential_Solution
Cur.execute("INSERT INTO TABLE ? values (?,Some_Var)",(Group_Name,User))
sqlite3.OperationalError: near "TABLE": syntax error
is there a practical way to do what I am trying to achieve? Or should I resort to another method?
I tried the following ,
you have to remove TABLE keyword use positional formatting
Cur.execute("INSERT INTO {0} VALUES('{1}', 'SomeVar')".format(Group_Name,User )
)
import sqlite3
def Database_Setup():
Cur.executescript(
"""
CREATE TABLE IF NOT EXISTS USERS
(
username text,
password text,
clearance int,
classes int
);
CREATE TABLE IF NOT EXISTS GROUPS
(
groupName text
teacher text,
teachingAssistant text
users
);
CREATE TABLE IF NOT EXISTS ASSIGNMENTS
(
assignmentID int,
assignmentName text,
assignmentInfo text,
dueDate date,
setDate date,
completedAmount int
)
"""
)
def Potential_Solution():
Group_Name = "Group1"
List_Of_Users = ["User1","User2","User3"]
Cur.execute("""
CREATE TABLE IF NOT EXISTS {}
(
username text,
randomVar text
)
""".format(Group_Name))
for User in List_Of_Users:
Cur.execute("INSERT INTO {0} VALUES('{1}', 'SomeVar')".format(Group_Name,User )
)
def Main():
Database_Setup()
Potential_Solution()
Cur.execute("SELECT * FROM Group1")
print(Cur.fetchall())
if __name__ == "__main__":
Conn = sqlite3.connect("FOO_DB.db")
Cur = Conn.cursor()
Main()

Access to a record just inserted [duplicate]

How to retrieve inserted id after inserting row in SQLite using Python? I have table like this:
id INT AUTOINCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50)
I insert a new row with example data username="test" and password="test". How do I retrieve the generated id in a transaction safe way? This is for a website solution, where two people may be inserting data at the same time. I know I can get the last read row, but I don't think that is transaction safe. Can somebody give me some advice?
You could use cursor.lastrowid (see "Optional DB API Extensions"):
connection=sqlite3.connect(':memory:')
cursor=connection.cursor()
cursor.execute('''CREATE TABLE foo (id integer primary key autoincrement ,
username varchar(50),
password varchar(50))''')
cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
('test','test'))
print(cursor.lastrowid)
# 1
If two people are inserting at the same time, as long as they are using different cursors, cursor.lastrowid will return the id for the last row that cursor inserted:
cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
('blah','blah'))
cursor2=connection.cursor()
cursor2.execute('INSERT INTO foo (username,password) VALUES (?,?)',
('blah','blah'))
print(cursor2.lastrowid)
# 3
print(cursor.lastrowid)
# 2
cursor.execute('INSERT INTO foo (id,username,password) VALUES (?,?,?)',
(100,'blah','blah'))
print(cursor.lastrowid)
# 100
Note that lastrowid returns None when you insert more than one row at a time with executemany:
cursor.executemany('INSERT INTO foo (username,password) VALUES (?,?)',
(('baz','bar'),('bing','bop')))
print(cursor.lastrowid)
# None
All credits to #Martijn Pieters in the comments:
You can use the function last_insert_rowid():
The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. The last_insert_rowid() SQL function is a wrapper around the sqlite3_last_insert_rowid() C/C++ interface function.
SQLite 3.35's RETURNING clause:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT
);
INSERT INTO users (first_name, last_name)
VALUES ('Jane', 'Doe')
RETURNING id;
returns requested columns of the inserted row in INSERT, UPDATE and DELETE statements. Python usage:
cursor.execute('INSERT INTO users (first_name, last_name) VALUES (?,?)'
' RETURNING id',
('Jane', 'Doe'))
row = cursor.fetchone()
(inserted_id, ) = row if row else None

Categories