How to create "ORDER BY Column = 'Value'" query with SQLAlchemy - sqlalchemy

I am new to SQLAlchemy & wanted to create an SQLAlchemy query equivalent to "order by exact match first".
Below is the SQL:
select word from dictionary where word like '%Time%' order by (word = 'Time') desc;
This is my SQLAlchemy equivalent.
Dictionary.query.with_entities ( Dictionary.word )
.filter(Dictionary.word.like("%{}%".format("Time")))
.order_by(Dictionary.word == "Time")
But it throws an error at "order_by": SyntaxError: keyword can't be an expression. How to solve it ?

Solved it.
from sqlalchemy.sql import func
.order_by(Dictionary.word == q,func.length(Dictionary.word))

Related

Using mysql '%' in date_format in Jupyter notebook

I try to use date_format in Jupyter notebook in my sql query to get the correct data but Jupyter throws the following error:
sql = "SELECT DATE_FORMAT(issues.created_on, "%Y") as YEAR, issues.tracker_id as Ticketgrund, count(*) FROM issues where issues.project_id = '2' group by YEAR, Ticketgrund;"
^
SyntaxError: invalid syntax"
Here is my cell:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sqlalchemy
session = sqlalchemy.create_engine("mysql+pymysql://user:pwj#ip/DB")
sql = "SELECT DATE_FORMAT(issues.created_on, "%Y") as YEAR, issues.tracker_id as Ticketgrund, count(*) FROM issues where issues.project_id = '2' group by YEAR, Ticketgrund;"
df = pd.read_sql_query(sql,session)
df.head(20)
The sql query runs without errors but not in jupyter. Escaping the %, which I assume to be the reason for error, does not change anything.
What can I do?
Escape the % with % (and use single quotes inside double quotes):
sql = "SELECT DATE_FORMAT(issues.created_on, '%%Y') as YEAR, issues.tracker_id as Ticketgrund, count(*) FROM issues where issues.project_id = '2' group by YEAR, Ticketgrund;"
Alternatively, use the date_format function available in SQLAlchemy. Here is a brief example:
from sqlalchemy import func
from sqlalchemy import MetaData, Table, Column
from sqlalchemy import select
from sqlalchemy import Integer, String, DateTime
md = MetaData()
mytable = Table(
"employees",
md,
Column("emp_no", Integer, primary_key=True),
Column("first_name", String(30)),
Column("last_name", String(30)),
Column("hire_date", DateTime),
)
row = session.execute( select(mytable.c.first_name, func.date_format(mytable.c.hire_date, "%Y") ) ).first()
print(row)

Using "IN" in importing data from a JSON to postgresql

I'm importing some data from a JSON file, but I can't use the IN operator in the query, as it generates an error. But it works when I use only 1 condition.
Below is the code:
with dados as (
select SPLIT_PART (sar_conteudo::text, 'header":', 2) as conteudo
from tb_gcc_situacao_arquivo
where sar_arquivo = 5012
--and sar_dt_movimento = '2022-01-12'), --> That's how it works
and sar_dt_movimento in ('2021-12-30','2021-12-31','2022-01-03')), --> not like this
dados_2 as (
select left (conteudo, length(conteudo)-1) as conteudo_2 from dados),
dados_final as(
SELECT *
from json_to_recordset((select * from dados_2)::json)
as x
("textoLinhaOriginal" text, "descricaoMensagem" text))
select
substring("textoLinhaOriginal",171,18) as captacao, "descricaoMensagem"
from dados_final
where "textoLinhaOriginal" ilike 'RDB 1INCL%'
and "descricaoMensagem" <> 'EXECUCAO OK'
Searching the internet, I noticed that the json_to_recordset only takes one line. So when passing more than 1 parameter, it will return an error message. How can I resolve this?
ERROR: more than one row returned by a subquery used as an expression

SQL: Binding an undef (NULL) to the placeholder will not select rows which have a NULL value

I'm using perl 5.20 and MySQL 5.7, but I think the question is about SQL in general:
perldoc DBI says:
Binding an undef (NULL) to the placeholder will not select rows which have a NULL age! At least for database engines that conform to the SQL standard. Refer to the SQL manual for your database engine or any SQL book for the reasons for this. To explicitly select NULLs you have to say "WHERE age IS NULL".
I don't even know what to google for... My question is: What are the reasons behind = ? not matching a binding to NULL/undef? (Beyond "that is how it is defined and documented".)
I've discovered that MySQL has an operator <=> that allows comparisons with NULL and so:
my $sth = $dbh->prepare('select count(*) from table where field <=> ?');
$sth->execute(345);
$sth->execute(undef);
both work as expected. Unfortunately, the doc says:
The <=> operator is equivalent to the standard SQL IS NOT DISTINCT FROM operator.
And MySQL doesn't support the IS NOT DISTINCT FROM operator :-(. So there seems to be no portable way to do this. Except for the very hackish:
my $sth = $dbh->prepare('
select count(*) from table
where field = ? OR ( ? IS NULL AND field IS NULL )
');
$sth->execute(345, 345);
$sth->execute(undef, undef);
or the even more hackish snippet from perldoc DBI
$sql_clause = defined $age? "age = ?" : "age IS NULL";
$sth = $dbh->prepare(qq{
SELECT fullname FROM people WHERE $sql_clause
});
$sth->execute(defined $age ? $age : ());
Is there a portable way to do WHERE FIELD = ? and have it do what I mean also with NULLs/undefs? What did I miss?
EDIT: I also came up with this workaround, which especially works great if field is a numeric type such as an INT, so we're sure the string "NULL" is not a possible non-NULL value.
my $sth = $dbh->prepare('
select count(*) from table
where COALESCE(field, "NULL") = COALESCE(?,"NULL")
');
$sth->execute(345);
$sth->execute(undef);
But performance goes out the window, as I don't think any indexes can be used....
I understand that this is not exactly what you asked for but if you use DBIx::Class, the ORM will do that lifting for you.
my $res = $schema->resultset('table')->search({ field => [345, undef] });
print $res->count;
It will be translated to this SELECT COUNT( * ) FROM table me WHERE ( ( field = ? OR field IS NULL ) ): '345'

SQLAlchemy MySQL IF Statement

I'm in the middle of converting an old legacy PHP system to Flask + SQLAlchemy and was wondering how I would construct the following:
I have a model:
class Invoice(db.Model):
paidtodate = db.Column(DECIMAL(10,2))
fullinvoiceamount = db.Column(DECIMAL(10,2))
invoiceamount = db.Column(DECIMAL(10,2))
invoicetype = db.Column(db.String(10))
acis_cost = db.Column(DECIMAL(10,2))
The query I need to run is:
SELECT COUNT(*) AS the_count, sum(if(paidtodate>0,paidtodate,if(invoicetype='CPCN' or invoicetype='CPON' or invoicetype='CBCN' or invoicetype='CBON' or invoicetype='CPUB' or invoicetype='CPGU' or invoicetype='CPSO',invoiceamount,
fullinvoiceamount))) AS amount,
SUM(acis_cost) AS cost, (SUM(if(paidtodate>0,paidtodate,invoiceamount))-SUM(acis_cost)) AS profit FROM tblclientinvoices
Is there an SQLAlchemyish way to construct this query? - I've tried googling for Mysql IF statments with SQlAlchemy but drew blanks.
Many thanks!
Use func(documentation) to generate SQL function expression:
qry = select([
func.count().label("the_count"),
func.sum(func.IF(
Invoice.paidtodate>0,
Invoice.paidtodate,
# #note: I prefer using IN instead of multiple OR statements
func.IF(Invoice.invoicetype.in_(
("CPCN", "CPON", "CBCN", "CBON", "CPUB", "CPGU", "CPSO",)
),
Invoice.invoiceamount,
Invoice.fullinvoiceamount)
)
).label("amount"),
func.sum(Invoice.acis_cost).label("Cost"),
(func.sum(func.IF(
Invoice.paidtodate>0,
Invoice.paidtodate,
Invoice.invoiceamount
))
- func.sum(Invoice.acis_cost)
).label("Profit"),
],
)
rows = session.query(qry).all()
for row in rows:
print row

sql alchemy : derived column example

#necessary import goes here
engine = sqlalchemy.create_engine('mysql://root#127.0.0.1/test',echo=False)
print 'Engine created'
connection=engine.connect()
metadata=MetaData(engine)
metadata.bind=engine
Session = sessionmaker(bind=engine)
session = Session()
mapping = Table('mapping',metadata,autoload=True)
class Mapping(object):
pass
MappingMapper=mapper(Mapping,mapping)
Now i am able to write basic query for insert,update,delete,filter etc.
Q:1 I need to write complex query, where i do derive new columns based on existing columns. Ex. ColA,ColB is there on table, ColC is not part of table structure.
Select (ColA+ColB) as ColC from table where ColC > 50 order by ColC.
I am clueless how to convert above like query with SqlAlchemy. How to map, how to retrieve.
The easiest is to useHybrid Attributes.
In your case, just change the declaration of the class to the following:
from sqlalchemy.ext.hybrid import hybrid_property
class Mapping(object):
#hybrid_property
def ColC(self):
return self.ColA + self.ColB
Then the query:
qry = session.query(Mapping).filter(Mapping.ColC > 80)
will generate SQL:
SELECT mapping.id AS mapping_id, ...
FROM mapping
WHERE mapping."ColA" + mapping."ColB" > ?