issues populating with_expression() in a subquery - sqlalchemy

I'm able to populate with_expression() just fine when I run a query, but when instead I convert that query into a subquery, it appears with_expression() is not working as expected and I do not get votes_sum variable.
class Comment(postgres_db.Model, Timestamp):
__tablename__ = 'comment'
id = postgres_db.Column(postgres_db.Integer, primary_key=True)
...
votes_sum = query_expression()
comments_votes_subquery = CommentVote.query. \
join(Comment). \
with_entities(CommentVote.comment_id,
functions.sum(CommentVote.vote).label("votes_sum")). \
group_by(CommentVote.comment_id). \
subquery()
comments_subquery = Comment.query. \
outerjoin(comments_votes_subquery, Comment.id == comments_votes_subquery.c.comment_id). \
options(with_expression(Comment.votes_sum, comments_votes_subquery.c.votes_sum)). \
subquery() # when this ins't a subquery, and I run comments_subquery.populate_existing().all(), I do get Comment.votes_sum data
threads_query = Thread.query. \
outerjoin(comments_subquery, Thread.comments). \
options(contains_eager(Thread.comments))
threads = threads_query.populate_existing().all()

Related

SQL trigger implementations

I am trying to write a mySql trigger for a website database. The backend uses django framework.
def add_trigger():
trigger = "CREATE TRIGGER update_ppl_rating \
BEFORE INSERT ON demosite_peoplerating \
FOR EACH ROW \
BEGIN \
DECLARE total integer; \
DECLARE sum integer; \
DECLARE avg float; \
SELECT COUNT(*) INTO total FROM demosite_peoplerating GROUP BY apart_key HAVING apart_key = NEW.apart_key; \
SELECT SUM(rating) INTO total FROM demosite_peoplerating GROUP BY apart_key HAVING apart_key = NEW.apart_key; \
SET avg = sum/total; \
UPDATE demosite_ratingtable \
SET ppl_rating = avg \
FROM demosite_ratingtable \
WHERE apart_key = NEW.apart_key \
END;"
cursor = connection.cursor()
cursor.execute(trigger)
cursor.close()
Here is the database model related:
class RatingTable(models.Model):
apart_key = models.ForeignKey(
'ApartmentFeature',
on_delete=models.CASCADE,
unique=True,
primary_key=True
)
env_rating = models.FloatField()
ppl_rating = models.FloatField()
rest_05_count = models.IntegerField()
rest_1_count = models.IntegerField()
rest_2_count = models.IntegerField()
shop_05_count = models.IntegerField()
shop_1_count = models.IntegerField()
shop_2_count = models.IntegerField()
class PeopleRating(models.Model):
comment_id = models.AutoField(primary_key=True)
apart_key = models.ForeignKey(
'ApartmentFeature',
on_delete=models.CASCADE,
)
rating = models.IntegerField()
comment = models.CharField(max_length=200)
nick_name = models.CharField(max_length=200)
After running add_trigger(), mysql server replies:
django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM demosite_ratingtable WHERE apart_key = NEW.apart_key END' at line 1")
Could you please any one give me tha idea to solve this?

Generate n-gram for a specific column present in mysql db

I'm writing a code to generate n-grams for every record in the table by reading a specific column.
def extract_from_db(inp_cust_id):
sql_db = TatDBHelper()
t_sql = "select notes from raw_data where customer_id = {0}"
db_data = sql_db.execute_read(t_sql.format(inp_cust_id))
for row in db_data:
text = row.values()
bi_grams = generate_ngrams(text[0].encode("utf-8"), 2)
print bi_grams
def generate_ngrams(sentence, n):
sentence = sentence.lower()
sentence = re.sub(r'[^a-zA-Z0-9\s]', ' ', sentence)
tokens = [token for token in sentence.split(" ") if token != ""]
ngrams = zip(*[tokens[i:] for i in range(n)])
return [" ".join(ngram) for ngram in ngrams]
I'm getting the output like:
['i highly', 'highly recommend', 'recommend it']
['the penguin', 'penguin encounter', 'encounter was', 'was awesome']
I want the output to look like below, can anybody help me to get this.
['i highly',
'highly recommend',
'recommend it',
...
]
creat another list all_ngrams, and keep appending the values to it , using .extend(), and finally you will have all the ngrams in one list.
Try this :
def extract_from_db(inp_cust_id):
sql_db = TatDBHelper()
t_sql = "select notes from raw_data where customer_id = {0}"
db_data = sql_db.execute_read(t_sql.format(inp_cust_id))
all_ngrams = []
for row in db_data:
text = row.values()
bi_grams = generate_ngrams(text[0].encode("utf-8"), 2)
all_ngrams.extend(bi_grams)
print all_ngrams

SQL Query to get data from before current time

Im trying to run a query that will allow me to pick out the rows that have the time before current time.
I want to pick out the rows that are before the current time not after. Am i able to order this in a way that can do can do this.
Currently this is my query.
var key = require('../validateApiKey');
// an example of executing a SQL statement directly
module.exports = {"get": [key,function (request, response, next) {
var query = {
sql: 'SELECT dbo.medicine.medname, \
dbo.medicine.packsize,\
dbo.medicine.id as "medicationid",\
dbo.usermedication.isactive, \
dbo.usermedication.reminder, \
dbo.usermedication.communityfeedback, \
dbo.usermedication.frequency, \
dbo.usermedication.directions, \
dbo.usermeddosagetime.usermedid, \
dbo.usermeddosagetime.time,\
dbo.usermedication.datetimetotake, \
dbo.usermeddosagetime.dosage,\
dbo.usermeddosagetime.dosageunit\
FROM dbo.usermedication INNER JOIN dbo.medicine ON dbo.usermedication.medicationid = dbo.medicine.id
INNER JOIN dbo.usermeddosagetime ON dbo.usermedication.id = dbo.usermeddosagetime.usermedid
WHERE dbo.usermedication.userid = #userid AND dbo.usermedication.isactive = 1',
parameters: [
{ name: 'userid', value: request.query.userid }
]
};
request.azureMobile.data.execute(query)
.then(function (results) {
response.json(results);
});
}]
};
Add the following condition to the WHERE clause:
MySQL
AND dbo.usermeddosagetime.time < NOW()
SQL Server
AND dbo.usermeddosagetime.time < GETDATE()

How do I prevent SQL injection when using the LIKE operator?

I am building a website using Node and the node-mysql package.
app.get('/api/tags', function(req, res) {
var term = req.query.term;
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + term + '%\' \
GROUP BY t.tagName \
LIMIT 5';
connection.queryAsync(query).spread(function(tags) {
tags = tags.map(function(tag) { return tag.tagName });
res.send(tags);
})
})
Here I use a value from the query string - term - to return a list of tags.
My question is: How do I prevent against SQL injection when I am using the LIKE operator?
I tried
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + conneciton.escape(term) + '%\' \
GROUP BY t.tagName \
LIMIT 5';
But that produces invalid SQL.
Try to never build an sql request by concatenation. It indeed always increases the risk of the SQL injection footprint.
A placeholder should work even with the LIKE condition.
var sql = '... LIKE ? GROUP BY ...';
connection.query(sql, ['%' + term + '%'], function(err, res) {})
A prepared statement would even be better for security concerns. you should read https://github.com/felixge/node-mysql/#escaping-query-values

Perl MySQL DBI - update and get last value

I am using the Perl DBI module with MySQL and trying to get the initial value before adding 1 to it when updating a row.
If the current value was 1000 I need to return the value of 1000 and then add 1 to the value.
I use this statement in perl to use one transaction...
update TABLE_NAME set ID = (\#cur_value := ID) + 1
I know I can do a select then an update as two statements or lock the tables manually but transactions happen so fast on our platform that it may cause inconsistencies and this is the fastest way to do it.
However I simply cannot find a way to return the original value before the increment using this statement.
It works fine in ASP as below:
qry = "update V15_TRACKING set TRACKING_ID = (#cur_value := TRACKING_ID) + 1 where TRACKING_TYPE='ABC'"
Set oRS = oConn.Execute(qry)
qry = "select #cur_value"
if not oRS.EOF then
while not oRS.EOF
CurrTrackingID = oRs.Fields("#cur_value")
oRS.movenext
wend
oRS.close
end if
Please can someone advise me what I need to do to return the original value in Perl as I have searched everywhere and tried all sorts of solutions.
A snippet to show what you're actually doing in perl, and your result would help diagnose what is going on in your script.
I tried this trivial example:
The DB:
CREATE DATABASE TEST;
CREATE TABLE foo (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
val int(11) NOT NULL
);
INSERT INTO foo (val) VALUES (1);
And the Perl
#!/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use DBI;
my $dbh = DBI->connect('DBI:mysql:database=test', 'dbuser', 'dbpass');
my $select = $dbh->prepare('SELECT * FROM foo WHERE id=?');
my $select_old_val = $dbh->prepare('SELECT #old_val');
my $update = $dbh->prepare('UPDATE foo SET val=(#old_val := val) + 1 WHERE id=?');
$update->execute(1);
$select_old_val->execute();
$select->execute(1);
while (my $row = $select_old_val->fetchrow_hashref) {
print Dumper $row;
}
while (my $row = $select->fetchrow_hashref) {
print Dumper $row;
}
And after a few goes:
$ perl select_and_update.pl
$VAR1 = {
'#old_val' => '10'
};
$VAR1 = {
'id' => '1',
'val' => '11'
};