How to parse SQL Queries and sub queries using sqlparser into python - python-2.7

Want to parse sql join query, select sub query into python. I am using sqlparse library. But i could not parse sub query. How i can parse whole query.
e.g:
query = "select id,fname,lname,address from res_users as r left join res_partner as p on p.id=r.partner_id where name = (select name from res_partner where id = 1)"
query_tokens = sqlparse.parse(query)[0].tokens
I could not parse for this select name from res_partner where id = 1 sub query.

Not so elegant, but works:
import sqlparse
from sqlparse.sql import Where, Comparison, Parenthesis
query = """
select
id,fname,lname,address
from
res_users as r
left join
res_partner as p
on
p.id=r.partner_id
where
name = (select name from res_partner where id = 1)"""
query_tokens = sqlparse.parse(query)[0]
where = next(token for token in query_tokens.tokens if isinstance(token, Where))
condition = next(token for token in where.tokens if isinstance(token, Comparison))
subquery = next(token for token in condition.tokens if isinstance(token, Parenthesis))
print subquery
prints:
(select name from res_partner where id = 1)

This library can parse and generate SQL https://code.google.com/p/python-sql/

Related

How is it possible to map column names from a Doctrine sql query?

I created a query with query builder like this:
$qb = $em->createQueryBuilder();
$qb->select(['u.id', 'u.name'])
->from(User::class, 'u')
->where('u.active = 1')
;
$sql = $qb->getQuery()->getSql();
The result looks like this:
SELECT u1_.user_id as s1, u1_.full_name as s2 FROM users u1_ WHERE u1_.is_active = 1
I would like to execute it as a native query, but I have to find out, how to map s1, s2 to id, name.
you have to use as inside your select
using your example =>
$qb = $em->createQueryBuilder();
$qb->select(['u.id as s1', 'u.name as s2'])
->from(User::class, 'u')
->where('u.active = 1');
$sql = $qb->getQuery()->getSql();
this maps id to s1 and name as s2
Not sure I understand your question but if you want to run a native query with, in the result, the columns id and name, you can replace them in the query, they're aliases so they can be anything you want :
SELECT u.user_id as id, u.full_name as name FROM users u WHERE u.is_active = 1

sqlite3 & python: get list of primary and foreign keys

I am very new to sql and intermediate at python. Using sqlite3, how can I get a print() list of of primary and foreign keys (per table) in my database?
Using Python2.7, SQLite3, PyCharm.
sqlite3.version = 2.6.0
sqlite3.sqlite_version = 3.8.11
Also note: when I set up the database, I enabled FKs as such:
conn = sqlite3.connect(db_file)
conn.execute('pragma foreign_keys=ON')
I tried the following:
conn=sqlite3.connect(db_path)
print(conn.execute("PRAGMA table_info"))
print(conn.execute("PRAGMA foreign_key_list"))
Which returned:
<sqlite3.Cursor object at 0x0000000002FCBDC0>
<sqlite3.Cursor object at 0x0000000002FCBDC0>
I also tried the following, which prints nothing (but I think this may be because it's a dummy database with tables and fields but no records):
conn=sqlite3.connect(db_path)
rows = conn.execute('PRAGMA table_info')
for r in rows:
print r
rows2 = conn.execute('PRAGMA foreign_key_list')
for r2 in rows2:
print r2
Unknown or malformed PRAGMA statements are ignored.
The problem with your PRAGMAs is that the table name is missing. You have to get a list of all tables, and then execute those PRAGMAs for each one:
rows = db.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
tables = [row[0] for row in rows]
def sql_identifier(s):
return '"' + s.replace('"', '""') + '"'
for table in tables:
print("table: " + table)
rows = db.execute("PRAGMA table_info({})".format(sql_identifier(table)))
print(rows.fetchall())
rows = db.execute("PRAGMA foreign_key_list({})".format(sql_identifier(table)))
print(rows.fetchall())
SELECT
name
FROM
sqlite_master
WHERE
type ='table' AND
name NOT LIKE 'sqlite_%';
this sql will show all table in database, for eache table run sql PRAGMA table_info(your_table_name);, you can get the primary key of the table.
Those pictures show what sql result like in my database:
first sql result
second sql result

Joining 2 results in Doctrine throws error

I am trying to JOIN 2 queries in DQL but I am getting an error which says,
[Semantical Error] line 0, col 114 near '(select u.email': Error: Class '(' is not defined.
I have gone through https://stackoverflow.com/questions/24600439/error-in-nested-subquery-in-dql-class-is-not-defined. But I could not figure out. Please help.
My Query is as follows:
$filterQuery = "SELECT tempResult1.email as email,tempResult1.name as name , tempResult1.id as user
FROM (select u.email as email,a.name as name , u.id as user
FROM
Application\Entity\Userhasrole uhr
INNER JOIN
Application\Entity\Oauthrole r with uhr.applicationrole = r.id
INNER JOIN
Application\Entity\Application a with r.application = a.id
INNER JOIN
Application\Entity\Oauthusers u
) tempResult1
LEFT JOIN
(SELECT uhr1.user as user FROM Application\Entity\Userhasrole uhr1 where
a.id = :applicationId
) tempResult2
with tempResult1.user = tempResult2.user";
$queryObject = $this->getEntityManager()
->createQuery($filterQuery);
$queryObject->setParameter('applicationId', $applicationId);
$result = $queryObject->getResult();
You mix 2 concepts of Doctrine2 :
using SQL
using DQL
If you want to achieve that you want, build tables selections, and not entities selections, you should use EntityManager::createNativeQuery() method and set an SQL query as parameter.
EntityManager::createQuery() is used only for DQL queries

Show tables, describe tables equivalent in redshift

I'm new to aws, can anyone tell me what are redshifts' equivalents to mysql commands?
show tables -- redshift command
describe table_name -- redshift command
All the information can be found in a PG_TABLE_DEF table, documentation.
Listing all tables in a public schema (default) - show tables equivalent:
SELECT DISTINCT tablename
FROM pg_table_def
WHERE schemaname = 'public'
ORDER BY tablename;
Description of all the columns from a table called table_name - describe table equivalent:
SELECT *
FROM pg_table_def
WHERE tablename = 'table_name'
AND schemaname = 'public';
Update:
As pointed by #Kishan Pandey 's answer, if you are looking for details of a schema different by public, you need to set search_path to my_schema. (show search_path display current search path)
Listing tables in my_schema schema:
set search_path to my_schema;
select * from pg_table_def;
I had to select from the information schema to get details of my tables and columns; in case it helps anyone:
SELECT * FROM information_schema.tables
WHERE table_schema = 'myschema';
SELECT * FROM information_schema.columns
WHERE table_schema = 'myschema' AND table_name = 'mytable';
Or simply:
\dt to show tables
\d+ <table name> to describe a table
Edit: Works using the psql command line client
Tomasz Tybulewicz answer is good way to go.
SELECT * FROM pg_table_def WHERE tablename = 'YOUR_TABLE_NAME' AND schemaname = 'YOUR_SCHEMA_NAME';
If schema name is not defined in search path , that query will show empty result.
Please first check search path by below code.
SHOW SEARCH_PATH
If schema name is not defined in search path , you can reset search path.
SET SEARCH_PATH to '$user', public, YOUR_SCEHMA_NAME
You can use - desc / to see the view/table definition in Redshift. I have been using Workbench/J as a SQL client for Redshift and it gives the definition in the Messages tab adjacent to Result tab.
In the following post, I documented queries to retrieve TABLE and COLUMN comments from Redshift.
https://sqlsylvia.wordpress.com/2017/04/29/redshift-comment-views-documenting-data/
Enjoy!
Table Comments
SELECT n.nspname AS schema_name
, pg_get_userbyid(c.relowner) AS table_owner
, c.relname AS table_name
, CASE WHEN c.relkind = 'v' THEN 'view' ELSE 'table' END
AS table_type
, d.description AS table_description
FROM pg_class As c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
LEFT JOIN pg_description As d
ON (d.objoid = c.oid AND d.objsubid = 0)
WHERE c.relkind IN('r', 'v') AND d.description > ''
ORDER BY n.nspname, c.relname ;
Column Comments
SELECT n.nspname AS schema_name
, pg_get_userbyid(c.relowner) AS table_owner
, c.relname AS table_name
, a.attname AS column_name
, d.description AS column_description
FROM pg_class AS c
INNER JOIN pg_attribute As a ON c.oid = a.attrelid
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
LEFT JOIN pg_description As d
ON (d.objoid = c.oid AND d.objsubid = a.attnum)
WHERE c.relkind IN('r', 'v')
AND a.attname NOT
IN ('cmax', 'oid', 'cmin', 'deletexid', 'ctid', 'tableoid','xmax', 'xmin', 'insertxid')
ORDER BY n.nspname, c.relname, a.attname;
Shortcut
\d for show all tables
\d tablename to describe table
\? for more shortcuts for redshift
redshift now support show table
show table analytics.dw_users
https://forums.aws.amazon.com/ann.jspa?annID=8641
You can simply use the command below to describe a table.
desc table-name
or
desc schema-name.table-name

psycopg2 strange behavior

from django.db import connection
q = 'some value'
sql1 = 'SELECT * FROM table WHERE field LIKE %%%s%%' % q
sql2 = 'SELECT * FROM table WHERE field LIKE %%'+ q +'%%'
cursor = connection.cursor()
cursor.execute( sql1 ) #why exception: IndexError: tuple index out of range ?
cursor.execute( sql2 ) #works ok
You need to QUOTE properly your SQL arguments.
And by quoting properly I mean using the quote facility provided by DBAPI, not adding a ' around your string, which is useless.
Correct code :
q = "%"+q+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Really correct code :
q = "%"+q.replace("%","%%")+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Suppose q = "a'bc"
First, rewrite this as "%a'bc%"
Then use it as a normal string argument. psycopg will rewrite it as '%a\'bc%' as it should.
If q may contain "%" and you want to search for it, then use the second one.
Using direct string manipulation will almost certainly lead to improper SQL that is vulnerable to SQL Injection attacks (see psycopg2's comments on the subject).
What I think you're looking to do is try and perform a LIKE '%some value%' in django, right?:
from django.db import connection
q = '%some value%'
cur = connection.cursor()
cur.execute("SELECT * FROM table WHERE field LIKE %(my_like)s", {'my_like': q})
As of psycopg2 2.4.1, the SQL that is executed on the server is:
SELECT * FROM table WHERE field LIKE '%some value%'
You need to QUOTE properly your SQL command:
sql1 = "SELECT * FROM table WHERE field LIKE '%%%s%%'" % q
sql2 = "SELECT * FROM table WHERE field LIKE '%"+ q +"%'"
And by quoting properly I mean using single quotes with LIKE expressions.