How to check if value is already exist in database (SQLAlchemy) - sql

I am trying to check if unique element is already present in postgresdb.
My method in views.py is
def bestfriend(username):
print username
user = Users.query.filter_by(username = username).first()
if user == None:
flash('bestfriend not found.')
return redirect(url_for('index'))
print user
u = g.user.friend(user)
#print bestfriend.id
if u is None:
#flash('Cannot be friend %(username)s.', username = username)
return redirect(url_for('user', username = username))
if db.session.query(bestfriend).filter(bestfriend.id==u.id).first():
flash('Already Exist')
return redirect(url_for('index'))
db.session.add(u)
db.session.commit()
flash('Your bestfriend has been added.')
return redirect(url_for('user', username = username))
My model.py is
bestfriend= db.Table('bestfriend',
db.Column('id',db.Integer, primary_key = True),
db.Column('friendid', db.Integer, db.ForeignKey('users.id'))
)
class Users(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key = True)
username = db.Column('username', db.String(20), unique=True , index=True)
password = db.Column('password' , db.String(10))
email = db.Column('email',db.String(50),unique=True , index=True)
registered_on = db.Column('registered_on' , db.DateTime)
posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
followed = db.relationship('Users',
secondary = followers,
primaryjoin = (followers.c.follower_id == id),
secondaryjoin = (followers.c.followed_id == id),
backref = db.backref('followers', lazy = 'dynamic'),
lazy = 'dynamic')
bestfriends = db.relationship('Users',
secondary = bestfriend,
primaryjoin = (bestfriend.c.friendid == id),
secondaryjoin = (bestfriend.c.id == id),
backref = db.backref('bestfriend', lazy = 'dynamic'),
lazy = 'dynamic')
I am able to insert value in database table bestfriend
Table "public.bestfriend"
Column | Type | Modifiers
----------+---------+-----------
id | integer | not null
friendid | integer |
Indexes:
"bestfriend_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"bestfriend_friendid_fkey" FOREIGN KEY (friendid) REFERENCES users(id)
but after insertion, I have to check if record is already present, using this line
if db.session.query(bestfriend).filter(bestfriend.id==u.id).first():
I am not sure about this statement. I have already tried similar solutions How to elegantly check the existence of an object/instance/variable and simultaneously assign it to variable if it exists in python? but it didn't worked for me.
I didn't receive any reply so adding some more info. I just want to check if id = 8 is already present in bestfriend table
app=> select * from bestfriend;
id | friendid
----+----------
8 | 11

Your statement does not work because bestfriend is a Table, not a mapped class. To fix the typo, just add c. to the query:
exists = db.session.query(bestfriend).filter(bestfriend.c.id==u.id).first()
Given that your relationship is defined as dynamic, you can do it easier with the following:
exists = user.bestfriends.filter(Users.id == u.id).one()
Side remark: Note that your bestfriend table is not structured correctly to allow many-to-many relationship. In order to do that, please change the definition of the table as per below:
bestfriend = db.Table('bestfriend',
db.Column('id',db.Integer, db.ForeignKey('users.id'), primary_key = True),
db.Column('friendid', db.Integer, db.ForeignKey('users.id'), primary_key = True)
)
Another remark: I do not understand the code flow: you add a friend at step u = g.user.friend(user), but later check if it exists. Shall logic not be reversed?

If you want to find if a record exists in a table, You can do it like this:
select 1 from table_name;
or better
select 1 from table_name where rownum=1;
The image below shows the query with output.
If there are any data, it will return 1 in the column.

Related

Cannot resolve logical: syntax error for sql

Not sure how to correct this logical syntax error, help would be appreciated!
Traceback (most recent call last):
File "c:\Users\M\Desktop\Coding\Course4wk4sql.py", line 7, in
cur.executescript('''
sqlite3.OperationalError: near "#logical": syntax error
PS C:\Users\M\Desktop\Coding> sqlite3.OperationalError: near "#logical": syntax error
Here is the code:
import json
import sqlite3
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 #logical key
);
CREATE TABLE Course (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
title TEXT UNIQUE
);
CREATE TABLE Member (
user_id INTEGER,
course_id INTEGER,
role INTEGER,
PRIMARY KEY (user_id, course_id) #Going to force combination of these two to be unique
)
''')
filename = "roster_data.json"
jsondata = open(filename)
data = json.load(jsondata)
for entry in data:
user = entry[0]
course = entry[1]
instructor = entry[2]
user_statement = """INSERT OR IGNORE INTO User(name) VALUE 9 ? )"""
SQLparams = (user, )
cur.execue(course_statement, SQLparams)
course_statement = """INSERT OR IGNORE INTO Course(title) VALUES ( ? )"""
sqlparams = (course, )
cur.execute(course_statement, SQLparams)
courseID_statement = """SELECT id FROM Course WHERE title = ?"""
SQLparams = (course, )
cur.execute(courseID_statement. SQLparams)
courseID =cur.fetone()[0]
userID_statement = """SELECT id FROM User WHERE name = ?"""
SQLparams = (user, )
cur.execute(userID_statement, SQLparams)
userID = cur.fetchone()[0]
member_statement = """INSERT INTO Member(user_id, course_id, role)
VALUES(?, ?, ?)"""
SQLparams = (userID, courseID, instructor)
cur.execute(member_statement, SQLparams)
conn.commit()
test_statement = """
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
"""
cur.execute(test_statement)
result = cur.fetchone()
print("RESULT: " + str(result))
#Closing the connection
cur.close()
conn.close()
You are using non-sql style comments eg #logical key in the sql script. While # is used for commenting in python -- or /* multi line comment */ is typically used in sqlite comments.
As a result you are getting a syntax error. You may remove these python style comments or attempt to replace them with sqlite style comments

SQLAlchemy DELETE: a foreign key contraint fails

I have the following two tables:
class User(Base):
__tablename__ = "user_entity"
id = Column(String(32), primary_key=True, index=True)
email = Column(String(32))
email_constraint = Column(String(32))
email_verified = Column(Boolean)
enabled = Column(Boolean)
federation_link = Column(String(32))
first_name = Column(String(32))
last_name = Column(String(32))
realm_id = Column(String(32))
username = Column(String(32))
created_timestamp = Column(String(32))
service_account_client_link = Column(String(32))
not_before = Column(Integer)
children = relationship("Userattribute", back_populates="parent")
class Userattribute(Base):
__tablename__ = "user_attribute"
name = Column(String(32))
value = Column(String(32))
id = Column(String(32), primary_key=True, index=True)
user_id = Column(String(32), ForeignKey('user_entity.id', ondelete="CASCADE"))
parent = relationship("User", back_populates="children")
I want to delete a user from the user_entity table by his ID:
[SQL: DELETE FROM user_entity WHERE user_entity.id = %s]
Delete implementation:
def delete_user(db: Session, id: str):
return db.query(models.User).filter_by(id=id)
#app.delete("/entity/{id}", response_model=schemas.Userentity)
def del_user(id: str, db: Session = Depends(get_db)):
user = crud.delete_user(db, id=id)
user_obj = user.first()
if user_obj is not None:
user.delete()
db.commit()
return JSONResponse(content={"message": "user erfolgreich gelöscht"})
else:
raise HTTPException(status_code=400, detail=f"ID existiert nicht")
Unfortunately I get the following error:
'Cannot delete or update a parent row: a foreign key constraint fails
Why does this fail? The expected behaviour is that when I delete a user, all user_attributes in the user_attribute table get also deleted. How to fix that?
I can't reproduce your error exactly: user.delete() raises an AttributeError. The correct call would be db.delete(user) I think.
The deletion behaviour must also be specified in the relationship on the parent:
children = relationship(
"Userattribute",
back_populates="parent",
cascade="all, delete"
)
For efficiency, you might also want to specify passive_deletes=True.
See Using foreign key ON DELETE cascade with ORM relationships.

sqlalchemy query from SQL with multiple where conditions

I have three tables which are defined as:
class User(Base):
__tablename__ = 'users'
id = Column(Integer(10), primary_key=True)
firstname = Column(String(64))
surname = Column(String(64))
class SWMS(Base):
__tablename__ = 'swms'
id = Column(Integer(10), primary_key=True)
owner_id = Column(Integer(10), ForeignKey('users.id', ondelete='CASCADE'))
filename = Column(String(255))
swmowner = relationship('User', backref=backref('users'))
class SWM_perms(Base):
__tablename__ = 'swm_perms'
id = Column(Integer(10), primary_key=True)
swm_id = Column(Integer(10), ForeignKey('swms.id', ondelete='CASCADE'))
user_id = Column(Integer(10), ForeignKey('users.id', ondelete='CASCADE'))
swm = relationship('SWMS', backref=backref('swms'))
swmuser = relationship('User', backref=backref('swmusers'))
Essentially, the SWMS table is a table of document info where the owner_id defines the user who created the document. SWM_perms is a table that has a mapping of document id to user id - to define which users are allowed to see the document.
To produce a table of all documents which are either 1) owned by the user or 2) are viewable by the user, in SQL I would do:
select owner_id, users.firstname, users.surname, filename
from swms, swm_perms, users
where users.id=swms.owner_id and
((swms.id=swm_perms.swm_id and swm_perms.user_id = 27) or (owner_id = 27));
How would you define this query in sqlalchemy? I am familiar with the or_() function but the variants I am trying do not generate the correct objects.
cond1 = and_(SWMS.id==SWM_perms.swm_id,SWM_perms.user_id==27)
swms = DBSession.query(User,SWMS).filter(or_(cond1,SWMS.owner_id==27)).\
filter(User.id==SWMS.owner_id).all()
and then you can do a list comprehension to pull the fields you want:
details = [(u.firstname, s.filename, s.blob_key, s.last_modified) for u,s in swms]
Also worth noting you can use the '&' operator, in place of 'and_', in the body of the query. See the example (second code block) they give here:
http://docs.sqlalchemy.org/en/rel_1_0/core/sqlelement.html#sqlalchemy.sql.expression.and_

Need some help accessing a ForeignKey row's data while performing a select with SQLAlchemy

Background Schema:
class Checkpoint(db.Model):
id = db.Column(db.Integer, primary_key=True)
creator = db.Column(db.Integer, db.ForeignKey('user.id'))
name = db.Column(db.String(255))
description = db.Column(db.String(255), nullable=True)
price = db.Column(db.Float, nullable=True)
expiry = db.Column(db.DateTime, nullable=True)
date_created = db.Column(db.DateTime)
type = db.Column(db.String(255))
image = db.Column(db.String(255))
longitude = db.Column(db.Float)
latitude = db.Column(db.Float)
class UserCheckpoint(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship("User")
checkpoint_id = db.Column(db.Integer, db.ForeignKey('checkpoint.id'))
checkpoint = db.relationship("Checkpoint")
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255))
facebook_info = db.Column(db.String(255), db.ForeignKey('facebook_user.id'))
facebook_user = db.relationship("FacebookUser")
class FriendConnection(db.Model):
id = db.Column(db.Integer, primary_key=True)
fb_user_from = db.Column(db.String(255), db.ForeignKey('facebook_user.id'))
fb_user_to = db.Column(db.String(255), db.ForeignKey('facebook_user.id'))
class FacebookUser(db.Model):
id = db.Column(db.String(255), primary_key=True)
name = db.Column(db.String(255))
first_name = db.Column(db.String(255), nullable=True)
middle_name = db.Column(db.String(255), nullable=True)
last_name = db.Column(db.String(255), nullable=True)
gender = db.Column(db.String(255), nullable=True)
username = db.Column(db.String(255), nullable=True)
link = db.Column(db.String(255), nullable=True)
I have a user, and as you can see, each user has a Facebook profile, as well as a table depicting inter-facebook-profile friendships. So given the user, the user would have a list of Facebook friends. I would like to get all UserCheckpoints that belong either to the user or his friends, with a given Checkpoint condition:
coord_conditions = and_(Checkpoint.longitude <= longitude + exp_no,
Checkpoint.longitude >= longitude - exp_no,
Checkpoint.latitude <= latitude + exp_no,
Checkpoint.latitude >= latitude - exp_no,
)
How can I do this using the ORM from SQLAlchemy? Thanks!
Summary: How to select UserCheckpoints given that the user_id belong to a list of friends/self; while UserCheckpoint.checkpoint has a set of conditions to fulfill.
Each relation has two methods to defined conditions on related objects: .has() for single referred object and .any() for collections. These methods allow straightforward translation of your task to SQLAlchemy expression. Let's add missing relations to FacebookUser:
class FacebookUser(Model):
# Definitions from question are here
user = relationship(User, uselist=False)
friends = relationship('FacebookUser',
secondary=FriendConnection.__table__,
primaryjoin=(id==FriendConnection.fb_user_from),
secondaryjoin=(FriendConnection.fb_user_to==id))
I've defined FacebookUser.user assuming one-to-one relation (which is usually supplemented with unique constraint on the foreign key column). Just remove uselist=False and adjust name if you allow several users being connected to one facebook account.
A shorter definition of your condition for coordinates:
coord_conditions = Checkpoint.longitude.between(longitude - exp_no,
longitude + exp_no) & \
Checkpoint.latitude.between(latitude - exp_no,
latitude + exp_no)
This condition is definitely wrong even for approximation (-179.9° and 179.9° are very close, while the difference is huge), but this is not main topic of the question.
A condition for users of interest (user with id equal to user_id and his friends):
user_cond = (User.id==user_id) | \
User.facebook_user.has(
FacebookUser.friends.any(FacebookUser.user.has(id=user_id)))
Now the query is quite simple:
session.query(UserCheckpoint).filter(
UserCheckpoint.checkpoint.has(coord_conditions) & \
UserCheckpoint.user.has(user_cond))
Unless you have (or expect) performance issues, I'd suggest avoid optimizing it at the cost of readability.
Basically your query can be split in two parts:
Given the user_id, create a list of users which will contain the user herself as well as all direct friends
Given the list of users from 1., get all UserCheckpoint whose Checkpoint would satisfy the criteria.
Not tested code:
# get direct user for given user_id
u1 = (session.query(User.id.label("user_1_id"), User.id.label("user_id"))
)
# get friends of the user in one direction (from other user to this one)
User2 = aliased(User)
FacebookUser2 = aliased(FacebookUser)
u2 = (session.query(User2.id.label("user_1_id"), User.id.label("user_id")).
join(FacebookUser2, User2.facebook_info == FacebookUser2.id).
join(FriendConnection, FacebookUser2.id == FriendConnection.fb_user_from).
join(FacebookUser, FacebookUser.id == FriendConnection.fb_user_to).
join(User, User.facebook_info == FacebookUser.id)
)
# get friends of the user in other direction (from this user to the other)
User2 = aliased(User)
FacebookUser2 = aliased(FacebookUser)
u3 = (session.query(User2.id.label("user_1_id"), User.id.label("user_id")).
join(FacebookUser2, User2.facebook_info == FacebookUser2.id).
join(FriendConnection, FacebookUser2.id == FriendConnection.fb_user_to).
join(FacebookUser, FacebookUser.id == FriendConnection.fb_user_from).
join(User, User.facebook_info == FacebookUser.id)
)
# create a union to have all pairs (me_or_friend_id, user_id)
u_all = union_all(u1, u2, u3)
# **edit-1: added alias **
u_all = u_all.alias("user_list_view")
# final query which adds filters requirested (by user_id and the checkpoint condition)
q = (session.query(UserCheckpoint).
join(Checkpoint).filter(coord_conditions).
join(u_all, UserCheckpoint.user_id == u_all.c.user_1_id).
filter(u_all.c.user_id == user_id)
)
for u_cp in q.all():
print u_cp
Note, that you could simplify the query somewhat if you defined more relationships in your model and then can remove some primaryjoin conditions from join clauses.

SQL to batch re-tag items

I've got a MySQL database with typical schema for tagging items:
item (1->N) item_tag (N->1) tag
Each tag has a name and a count of how many items have that tag
ie:
item
(
item_id (UNIQUE KEY)
)
item_tag
(
item_id (NON-UNIQUE INDEXED),
tag_id (NON-UNIQUE INDEXED)
)
tag
(
tag_id (UNIQUE KEY)
name
count
)
I need to write a maintenance routine to batch re-tag one or more existing tags to a single new or existing other tag. I need to make sure that after the retag, no items have duplicate tags and I need to update the counts on each tag record to reflect the number of actual items using that tag.
Looking for suggestions on how to implement this efficiently...
if i understood you correctly then you could try something like this:
/* new tag/item table clustered PK optimised for group by tag_id
or tag_id = ? queries !! */
drop table if exists tag_item;
create table tag_item
(
tag_id smallint unsigned not null,
item_id int unsigned not null,
primary key (tag_id, item_id), -- clustered PK innodb only
key (item_id)
)
engine=innodb;
-- populate new table with distinct tag/items
insert ignore into tag_item
select tag_id, item_id from item_tag order by tag_id, item_id;
-- update counters
update tag inner join
(
select
tag_id,
count(*) as counter
from
tag_item
group by
tag_id
) c on tag.tag_id = c.tag_id
set
tag.counter = c.counter;
An index/constraint on the item_tag table can prevent duplicate tags; or create the table with a composite primary key using both item_id and tag_id.
As to the counts, drop the count column from the tag table and create a VIEW to get the results:
CREATE VIEW tag_counts AS SELECT tag_id, name, COUNT(*) AS count GROUP BY tag_id, name
Then your count is always up to date.
This is what I've got so far, which seems to work but I don't have enough data yet to know how well it performs. Comments welcome.
Some notes:
Had to add a unique id field to to the item_tags table get the duplicate tag cleanup working.
Added support for tag aliases so that there's a record of retagged tags.
I didn't mention this before but each item also has a published flag and only published items should affect the count field on tags.
The code uses C#, subsonic+linq + "coding horror", but is fairly self explanatory.
The code:
public static void Retag(string new_tag, List<string> old_tags)
{
// Check new tag name is valid
if (!Utils.IsValidTag(new_tag))
{
throw new RuleException("NewTag", string.Format("Invalid tag name - {0}", new_tag));
}
// Start a transaction
using (var scope = new SimpleTransactionScope(megDB.GetInstance().Provider))
{
// Get the new tag
var newTag = tag.SingleOrDefault(x => x.name == new_tag);
// If the new tag is an alias, remap to the alias instead
if (newTag != null && newTag.alias != null)
{
newTag = tag.SingleOrDefault(x => x.tag_id == newTag.alias.Value);
}
// Get the old tags
var oldTags = new List<tag>();
foreach (var old_tag in old_tags)
{
// Ignore same tag
if (string.Compare(old_tag, new_tag, true)==0)
continue;
var oldTag = tag.SingleOrDefault(x => x.name == old_tag);
if (oldTag != null)
oldTags.Add(oldTag);
}
// Redundant?
if (oldTags.Count == 0)
return;
// Simple rename?
if (oldTags.Count == 1 && newTag == null)
{
oldTags[0].name = new_tag;
oldTags[0].Save();
scope.Complete();
return;
}
// Create new tag?
if (newTag == null)
{
newTag = new tag();
newTag.name = new_tag;
newTag.Save();
}
// Build a comma separated list of old tag id's for use in sql 'IN' clause
var sql_old_tags = string.Join(",", (from t in oldTags select t.tag_id.ToString()).ToArray());
// Step 1 - Retag, allowing duplicates for now
var sql = #"
UPDATE item_tags
SET tag_id=#newtagid
WHERE tag_id IN (" + sql_old_tags + #");
";
// Step 2 - Delete the duplicates
sql += #"
DELETE t1
FROM item_tags t1, item_tags t2
WHERE t1.tag_id=t2.tag_id
AND t1.item_id=t2.item_id
AND t1.item_tag_id > t2.item_tag_id;
";
// Step 3 - Update the use count of the destination tag
sql += #"
UPDATE tags
SET tags.count=
(
SELECT COUNT(items.item_id)
FROM items
INNER JOIN item_tags ON item_tags.item_id = items.item_id
WHERE items.published=1 AND item_tags.tag_id=#newtagid
)
WHERE
tag_id=#newtagid;
";
// Step 4 - Zero the use counts of the old tags and alias the old tag to the new tag
sql += #"
UPDATE tags
SET tags.count=0,
alias=#newtagid
WHERE tag_id IN (" + sql_old_tags + #");
";
// Do it!
megDB.CodingHorror(sql, newTag.tag_id, newTag.tag_id, newTag.tag_id, newTag.tag_id).Execute();
scope.Complete();
}