Querying in Python - python

I'm building a database on python 2.7 using sqlite3 and I have reached a small problem.
Basically I have two tables which each store the following information:
Tweet:
user_name,
tweet_time,
tweet_text
User:
user_name,
user_description,
user_followers,
user_verified,
user_location
I am trying to add a function which prompts the user to enter a string, and every row in both tables which contains the submitted string, which will be found in the tweet_text column, is deleted.
The problem I'm having is that the 'User' Table does not contain a column tweet_text so I'm not sure how to delete corresponding rows in this table without actually having to add a tweet_text column.
What I have so far is just a simple delete query on the 'Tweet' Table.
delete_string = raw_input("Which string would you like to be removed from your database?: ")
c.execute("DELETE FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',))
I'm wondering if there is any way to delete the corresponding rows in the 'User' Table without having to explicitly include tweet_text as a column.
I'm relatively inexperienced on python and this is my first time using query writing so any help will be greatly appreciated!
Thanks in advance.

I just wrote this from my mind but try this query:
DELETE tweet, user
FROM Tweet tweet JOIN User user ON tweet.user_name = user.user_name
WHERE tweet.tweet_text LIKE ?;
Although what you're looking for is this, ON DELETE CASCADE.
That will automatically delete it from foreign key table, which will be your User table.
Make sure to enable foreign key support in SQLite
PRAGMA foreign_keys = ON;

According to your question, you may delete by querying the username using the tweet_text column but I do not believe you wish to delete the username if you have 2 tweets from the same user and you delete one.
I would probably suggest this:
# Fetch all users with a tweet_text that is similar to the delete_string
res = c.execute("SELECT user_name FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',)).fetchall()
# If any user is found
if res:
# Get his username
user_name = res[0][0]
# Delete the tweet
c.execute("DELETE FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',))
# If he has no more tweets in the database
if c.execute("SELECT 1 FROM Tweet WHERE user_name = ?", (user_name)).fetchone() is None:
# Delete the user.
c.execute("DELETE FROM User WHERE user_name = ?", (user_name))
First you fetch the user_name if the tweet exists
Then you delete the tweet
Then you check if there are more tweets from the same user.
If there are none you delete him from the database.
If you wish, you may support multiple users like so:
# Get all users with similar tweets
res = c.execute("SELECT user_name FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',)).fetchall()
# If there are any
if res:
# Get their user names (make it a set to avoid repeated names)
user_names = set(u[0] for u in res)
# Delete all the similar tweets
c.execute("DELETE FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',))
for user in user_names:
# Check for each user if he has more tweets in the database
if c.execute("SELECT 1 FROM Tweet WHERE user_name = ?", (user,)).fetchone() is None:
# If he has none, delete him.
c.execute("DELETE FROM User WHERE user_name = ?", (user_name))
UPDATE:
If you have the same amount of rows, you must have an identifier(rowid) which will tie the tweet and the user. Define the tweet database as so: (The important part is the identifier)
identifier INTEGER PRIMARY KEY AUTOINCREMENT,
user_name TEXT,
tweet_time DATETIME,
tweet_text TEXT
And the User database as so:
identifier PRIMARY KEY,
user_name TEXT,
user_description TEXT,
...
Upon inserting rows to the tweet database, use cursor.lastrowid in order to fetch the generated identifier and insert the generated identifier together with the user to the Users database. You should probably do it in the same transaction. Upon deleting, delete from both databases where the identifier is the same.
See this stackoverflow question and the sqlite documentation regarding rowid or identifier columns.
Here's an example:
# When adding
with connection:
cursor = connection.execute("INSERT INTO Tweet (user_name, tweet_time, tweet_text) VALUES (?, ?, ?)", (user, time, text))
rowid = cursor.lastrowid
cursor.execute("INSERT INTO User (identifier, user_name, user_description, ...) VALUES (?, ?, ?, ...", (rowid, user, desc, ...))
# When deleting
tweet_ids = c.execute("SELECT identifier FROM Tweet WHERE tweet_text LIKE ?", ('%'+delete_string+'%',)).fetchall()
if tweet_ids:
cursor.executemany("DELETE FROM Tweet WHERE identifier = ?", tweet_ids)
cursor.executemany("DELETE FROM User WHERE identifier = ?", tweet_ids)
# Or one line when deleting (I'm not sure if it works)
c.execute("DELETE tweet, user FROM Tweet tweet JOIN User user "
"ON tweet.identifier = user.identifier "
"WHERE tweet.tweet_text LIKE ?", ('%'+delete_string+'%',))

Related

How to create working like button in flask and sqlite3?

I am trying to create a social network using flask and sqlite3. I had created almost all the main things like post, edit post, delete post. But I also want to add the like button for every post. I had created like number(How many like this post got) and like button and it is working fine but If you like my post for the first time and again login your account then you can again like that post which you had already liked by your account.
I had an idea to save who liked my post but i don't know how to implement that exact code in my webapp.I am using sqlite3 so I am not finding any solution for this issue. I had found exactly same question for mysql or any other database but I had not for sqlite3.
Ok here is my idea,
I had already mentioned that I am using sqlite3 so I had created table like this:
conn=sqlite3.connect('data/detailpost.db')
c=conn.cursor()
c.execute("""CREATE TABLE postdetail(
name text,
address text,
post text,
post_date text,
secretcode text,
mainname text,
likes integer,
likers text)""")
conn.commit()
conn.close()
and If someone click like button(In template) then that will come in this part of back-end where I am getting liker mainname and oid number of that post.And this is the same back-end code which increase the like of the post. Like this
#app.route('/social/post/like',methods=['POST'])
def likedofsocial():
if request.method=='POST':
oid=request.form['oid']
mainusernameofliker=request.form['username']
conn=sqlite3.connect('data/detailpost.db')
c=conn.cursor()
c.execute("SELECT *,oid FROM postdetail WHERE oid="+oid)
alldata=c.fetchall()
for rec in alldata:
c.execute("""UPDATE postdetail SET
name=:name,
address=:address,
post=:post,
post_date=:datee,
secretcode=:secret,
mainname=:mainname,
likes=:likes
likers=:likers
WHERE oid=:num""",
{
'name':rec[0],
'address':rec[1],
'post':rec[2],
'datee':rec[3],
'secret':rec[4],
'mainname':rec[5],
'likes':(int(rec[6]+1)),
'likers':mainusernameofliker,
'num':oid,
})
conn.commit()
conn.close()
.....
Here in this above part I don't know how to save multiple mainusernameofliker inside likers beacause there will not be only one person who likes my posts.
Now I have only idea for front-end I had not tried any of the code which is mentioned below!! I just think following code could works fine
"For front-end check that likers data and
(% if (your mainusername is in that likers data ) %)
then show already liked(Liked) or disable like button
(% else (your username is not in that likers data) %)
then that show like or make clickable like button".
(% endif %)
Probably, I could get help as soon as possible and any help will be appreciated.
I think your main question is that how to store the multiple users who would like the post. It is very simple, you just need to create one more table maybe called postlikers. This table will reference primary keys of user and postdetail. Basically a many-to-many relationship between user and postdetail tables.
I will show you an example that how you can define the tables below:
import sqlite3
conn=sqlite3.connect('detailpost.db')
c=conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS user(
id INTEGER PRIMARY KEY,
name text)
""")
c.execute("""CREATE TABLE IF NOT EXISTS postdetail(
id INTEGER PRIMARY KEY,
name text,
address text,
post text,
post_date text,
secretcode text,
mainname text,
likes integer DEFAULT 0
)""")
c.execute("""CREATE TABLE IF NOT EXISTS postlikers(
id INTEGER PRIMARY KEY,
post_id INTEGER,
user_id INTEGER,
FOREIGN KEY(post_id) REFERENCES postdetail(id),
FOREIGN KEY(user_id) REFERENCES user(id)
)
""")
conn.commit()
conn.close()
# Add data
user_data = [('Carl'), ('Mel'), ('Bobby')]
post_data = [('first_post', 'whajjne', 'I love everything', 'dfweffwwffefe', 'secret', 'Carl', 0),
('second_post', 'whajjne', 'I love everything', 'dfweffwwffefe', 'secret', 'Mel', 0)]
conn=sqlite3.connect('detailpost.db')
c=conn.cursor()
for user in user_data:
c.execute('INSERT INTO user (name) VALUES (?);', (user,))
for post in post_data:
c.execute('INSERT INTO postdetail (name, address, post, post_date, secretcode, mainname,likes ) VALUES (?,?,?,?,?,?, ?);', post)
conn.commit()
conn.close()

How to show different data to different users in flask application?

I have created a flask application and using mysql as DB backend and this is used by multiple users simultaneously.
The problem I'm having is,In my homepage a select query is performed and data is displayed to the user but same data is showing to all users.it should be unique. I have tried to lock the row by using FOR UPDATE while selecting the row. I know that I'm not updating the row,so the transaction will be closed when the function ends and the row will be released from lock.
How to overcome this problem?
Expected output: Each user should get different data from the table.(Even when they refresh)
#is_logged_in
#app.route('/')
def index():
conn = mysql.connection
cur = conn.cursor()
cur.execute("select mylist ,myurl ,swatch,parent from image_links where status =%s LIMIT 1 FOR UPDATE",("fetched",))
parent = cur.fetchall()
for row in parent:
mylistitems = row[0].split(",")
swatches = row[2].split(",")
myurlsitems = row[1].split(",")
pid = row[3]
if asinlist != ['']:
merged = tuple(zip(mylistitems ,myurlsitems ,swatches))
return render_template('home.html',firstimage= myurlsitems[0],merged=merged)
else:
cur.execute("UPDATE asin_links SET status = %s WHERE pid= %s", ("invalid",pid,))
conn.commit()
return redirect(url_for('index'))
I can't see any "current user" specific parameters used in your sql query or any data filtering decided on some user ID.
Basically, if you are running the same code, same query for all requests on this endpoint, it will never be really unique. You need to add some user specific checks so you can differentiate the output for the current requesting user.
Depending on your use-case and database models, if the data in the table image_links is also created/inserted by some user action you might want additionally save some user ID alongside these values, eg. by extending the table model with another "user_id" column and on insert also add the id of the current user.
You are using some auth decorator #is_logged_in, if you are already handling users in some table then the another user_id column could be a reference to the respective user's primary key. Then, in your example, you would just add additional where user_id = check with the current user's primary key.
As I see in this SQL query:
SELECT mylist, myurl, swatch, parent FROM image_links WHERE status
perhaps you did specify the related user to get its own specific data, try to replace that last "where" with:
WHERE id = (user.id) --> user object
or you could use the AND keyword, something like
WHERE status = (x) AND id = (y)

Selecting data from multiple tables that have no foreign keys?

I have this current sqlite3 code in my python file:
Data = Cursor.execute("""
SELECT Username, Password
FROM PatientTable
WHERE Username = '{}'
""".format(Username))
Data = Data.fetchall()
There are multiple tables in the database: PatientTable, DoctorTable, ManagerTable. Each one has attributes of Username and Password in the second and third column respectively.
Q: My current code only selects data from PatientTable but I need to select data from all three tables and identify which table each item of data came from.
Now, I think I can do this using multiple SQL statements but this seems excessive. I have thought about using JOIN but there are no foreign keys - keys relating the databases to each other.
Thanks in advance.
You seem to be looking for UNION. You can add a fixed column to each query to distinguish from which table each record in the resultset comes from :
SELECT 'PatientTable' source_table, Username, Password
FROM PatientTable
WHERE Username = '{}'
UNION ALL SELECT 'DoctorTable' , Username, Password
FROM DoctorTable
WHERE Username = '{}'
UNION ALL SELECT 'ManagerTable', Username, Password
FROM ManagerTable
WHERE Username = '{}'

SQL Query returning "None" instead of row

I'm working on a light login, and have a tabled titled Users. I'm trying to take my login form POST body and verify it across the database.
Values from form:
user = request.form['username']
password = request.form['password']
SQL Statement:
conn = sqlite3.connect(db)
cur = conn.cursor()
cur.execute("SELECT * FROM Users WHERE Username LIKE '(%s)'" % user)
row = cur.fetchone()
Users Table:
So on a POST request from my form, here is what is printed:
Print(user, password) = ph104694 Password123
Print(row) = None
So you can see the row is being returned as None when the data absolutely exists. If I change user to something I know is incorrect, I'm getting the same results, but if I change the table from Users to something like Users2 I'm met with a no table exists error which is fine. So despite matching data existing something about my statement isn't allowing it to produce that row. Any ideas?
You're search expression is evaluating to (ph104694) which clearly doesn't exist in the data you showed.
There is no reason to use the LIKE operator here and it probably runs counter to what you want to do (match the single record exactly matching the user ID that was entered).
This is the classic example of code that is subject to an SQL injection attack. You should never, never, ever use string interpolation to build an SQL string like this. Instead, use parameter substitution.
Taken all together, you want something like this:
cur.execute("SELECT * FROM Users WHERE Username = ?", [user])
Your query string evaluates to "SELECT * FROM Users WHERE Username LIKE '(ph104694)'".
Note the parentheses which aren't in the actual username.
Also, you almost certainly don't want to use LIKE.
What you want is "SELECT * FROM Users WHERE Username = 'ph104694'"
Which would create with "SELECT * FROM Users WHERE Username = '{user}'".format(user=user)
Also, you can (and should) parameterize this as
cur.execute("SELECT * FROM Users WHERE Username = :user", {user: user})

Using foreign keys in sqlite3 for Python

I'm writing a program that creates a sqlite3 database through python. I have one table of Authors (AuthorID, Name) and a second table of books (BookID, Title, AuthorID) I've created these as shown below:
Authors = sqlite3.connect('Authors.db')
Authors.execute('''CREATE TABLE Authors
(AuthorID INT PRIMARY KEY,
Name TEXT);''')
Authors.close()
Books = sqlite3.connect('Books.db')
Books.execute('''CREATE TABLE Books
(BookID INT PRIMARY KEY,
Title TEXT,
AuthorID INT,
FOREIGN KEY(AuthorID) REFERENCES Authors(AuthorID));''')
Books.close()
I then go to add a record to each of the tables as shown below:
Authors = sqlite3.connect('Authors.db')
Authors.execute("INSERT INTO Authors (AuthorID, Name) \
VALUES (1, 'Jane Austin')");
Authors.commit()
Authors.close()
Books = sqlite3.connect('Books.db')
Books.execute("INSERT INTO Books (BookID, Title, AuthorID) \
VALUES (1, 'Emma', 1)");
Books.commit()
Books.close()
The database is correctly updated but I don't think the foreign keys are working correctly because it allows me to remove the Author 'Jane Austin', when there are books associated with it.
I've seen some tutorials use this line:
Books.execute("PRAGMA foreign_keys = 1")
Is this the answer to the problem and if so where do I put this line?
The PRAGMA foreign_keys setting applies to a connection, so you should execute it immediately after calling sqlite3.connect().
Please note that foreign key constraints work only inside the same database; you should put both tables into the same file.
So to do what you want to do you need to create one database file with 2 tables.
Example:
conn=sqlite3.connect("clientdatabase.db")
conn.execute("PRAGMA foreign_keys = 1")
cur=conn.cursor()
# Create 2 tables if they don't exist: Clients and Work_Done
cur.execute('''CREATE TABLE IF NOT EXISTS Clients
(CID INTEGER PRIMARY KEY,
First_Name TEXT NOT NULL,
Last_Name TEXT,
Business_Name TEXT,
Phone TEXT,
Address TEXT,
City TEXT,
Notes TEXT,
Active_Status TEXT NOT NULL)''')
cur.execute('''CREATE TABLE IF NOT EXISTS Work_Done
(ID INTEGER PRIMARY KEY,
Date TEXT NOT NULL,
Onsite_Contact TEXT,
Work_Done TEXT NOT NULL,
Parts_Installed TEXT,
Next_Steps TEXT,
CID INT,
FOREIGN KEY (CID) REFERENCES CLIENTS (CID))''')
conn.commit()
Note that both tables are in the same database and you add the line after connection and before the cursor object.
Hope this helps.
Also note that if there is an active transaction, the PRAGMA foreign_keys does not work. There is no error message if you try to do so but foreign keys will still be turned off.
If you have problems with foreign keys even after using the pragma, it may be worth an attempt to execute COMMIT once before using it.
FYI, according to the recent official document, you can use PRAGMA foreign_keys = ON.
connection = sqlite3.connect(DB_FILE)
connection.execute('PRAGMA foreign_keys = ON')
cursor = connection.cursor()
(...)

Categories

Resources