· 9 years ago · Aug 03, 2017, 11:22 AM
1from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, MetaData
2from sqlalchemy import create_engine
3from sqlalchemy.sql import select
4import psycopg2
5
6import pandas as pd
7
8# create_engine Ñоздаёт движок Ð´Ð»Ñ Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ Ð±Ð°Ð·Ð¾Ð¹ данных
9# общий вид: 'postgresql+psycopg2://postgres:Jdghsieurgmx@localhost:5432/postgres'
10dialect = "postgresql"
11db_engine = "psycopg2" # библиотека Ñ€ÐµÐ°Ð»Ð¸Ð·ÑƒÑŽÑ‰Ð°Ñ Ð´Ð¾Ñтуп к БД. Ð’ документации называетÑÑ engine, Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ°Ñ ÐºÐ¾Ð»Ð»Ð¸Ð·Ð¸Ñ
12user = "postgres"
13password = "Jdghsieurgmx"
14hostname = "localhost"
15db_port = "5432"
16db_name = "postgres"
17# PosgreSQL ÑвлÑетÑÑ Ð¡Ð£Ð‘Ð”, Ñ‚.е. ÑиÑтемой ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ð°Ð¼Ð¸ данных.
18# Внутри можно Ñоздавать много баз Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ‡ÐºÐ°Ð¼Ð¸, и вот Ð¸Ð¼Ñ Ñ‚Ð°ÐºÐ¾Ð¹ базы и передаётÑÑ Ð² параметрах
19
20engine = create_engine('{0}+{1}://{2}:{3}@{4}:{5}/{6}'.format(dialect, db_engine, user, password, hostname, db_port, db_name))
21
22# взаимодейÑтвие Ñ Ð±Ð°Ð·Ð¾Ð¹ оÑущеÑтвлÑетÑÑ Ñ‡ÐµÑ€ÐµÐ· Ñоединение
23conn = engine.connect()
24
25# БЛОК С SQL ЗÐПРОСÐМИ
26# SQL Ð°Ð»Ñ…Ð¸Ð¼Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет иÑполнÑть готовые SQL запроÑÑ‹
27
28# Смотрим какие таблицы уже еÑть
29for name in conn.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'test_schema'"): print(name)
30# Результат:
31('test_table',)
32('gwas_descriptors',)
33('df_sql_test',)
34
35# во второй чаÑти запроÑа: WHERE table_schema='test_schema' указываем Ð´Ð»Ñ ÐºÐ°ÐºÐ¾Ð¹ Ñхемы выпиÑать имена таблиц
36# еÑли не указывать Ñхему, то Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð±ÑƒÐ´ÐµÑ‚ в виде SELECT table_name FROM information_schema.tables и покажет имена ещё и ÑиÑтемных таблиц
37
38# при обращении Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð°Ð¼Ð¸ надо указать Ñхему которой принадлежит таблица: test_schema.gwas_descriptors
39# Сколько запиÑей в gwas_description?
40for result in conn.execute("SELECT COUNT(*) FROM test_schema.gwas_descriptors"): print(result)
41# Результат:
42(5,)
43
44# Зачем поÑтоÑнно пиÑать for in?
45# на Ñамом деле conn.execute возвращает итератор(в терминах базы данных казываетÑÑ ÐºÑƒÑ€Ñор) по результатам. Ðто нужно Ð´Ð»Ñ Ð²ÑÑких хитрых оптимизаций
46# подробноÑти https://postgrespro.ru/docs/postgrespro/9.6/plpgsql-cursors
47# ЕÑли вы ЗÐÐЕТЕ что результатов будет не много, то можете обернуть Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð² лиÑÑ‚
48# РеÑли не уверены, то выберите только первые N вот так:
49list(conn.execute("SELECT * FROM test_schema.gwas_descriptors LIMIT 2"))
50# хотим поÑмотреть на дживаÑÑ‹ из gwas_descriptors
51list(conn.execute("SELECT * FROM test_schema.gwas_descriptors"))
52# Результат:
53[(1, '/home/storage/data/gwas_raw/FG/FG.txt',...)
54(1, '/home/storage/data/gwas_raw/FG/FG.txt',...)
55...
56
57# круто, но какие же Ñтолбцы
58list(conn.execute("SELECT column_name FROM information_schema.columns WHERE table_name = 'gwas_descriptors'"))
59# Результат:
60[('gwas_id',)
61('path',)
62('base_dir',)
63...
64
65# оÑобенноÑтью работы Ñ conn.execute ÑвлÑетÑÑ Ñ‚Ð¾, что курÑор уничтожаетÑÑ ÐºÐ¾Ð³Ð´Ð° вÑе данные выбраны.
66# например
67gwases = conn.execute("SELECT * FROM test_schema.gwas_descriptors")
68for gwas in gwases: print(gwas[1])
69# Result
70/home/storage/data/gwas_raw/FG/FG.txt
71/home/storage/data/gwas_raw/FG/FG.txt
72...
73# но еÑли запуÑтить ешё раз, то результаты будут пуÑтыми, Ñ‚.к. Ð´Ð»Ñ Ð±Ð°Ð·Ñ‹ курÑор уже выбрал результаты в предыдущий раз
74
75# И вÑегда работать Ñ Ð¼Ð°ÑÑивом?
76# Результаты можно загружать в pandas dataframe вот так:
77df = pd.read_sql_query("""SELECT * FROM test_schema.gwas_descriptors""", con = engine)
78
79# Ð”Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи данных из pd обратно в таблицу еÑть неÑколько Ñтратегий:
80# if_exists
81# fail: If table exists, do nothing.
82# replace: If table exists, drop it, recreate it, and insert data.
83# append: If table exists, insert data. Create if does not exist.
84# Ðапример нижнÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° допишет в конец данные из df
85df.to_sql('gwas_descriptors', engine, schema = 'test_schema', index = False, if_exists = 'append')
86
87
88# ПÐМЯТКРПО БÐЗОВЫМ SQL КОМÐÐДÐМ
89
90# выбрать только пути до gwas и gwas_id (именно в таком порÑдке)
91list(conn.execute("SELECT path, gwas_id FROM test_schema.gwas_descriptors"))
92# на меÑте path может быть любое поле из базы данных
93
94# чтобы выбирать не Ð´Ð»Ñ Ð²Ñех, надо опиÑать параметры по которым будут выбраны запиÑи
95# например только дживаÑÑ‹ Ñ gwas_id=1
96list(conn.execute("SELECT path FROM test_schema.gwas_descriptors WHERE gwas_id = 1"))
97
98# изменить gwas_id:
99conn.execute("UPDATE test_schema.gwas_descriptors SET gwas_id=2 WHERE gwas_id = 1")
100
101# удалить у которых gwas_id
102conn.execute("DELETE FROM test_schema.gwas_descriptors WHERE gwas_id = 1")
103
104# Ð’Ñе SQL команды вы можете запуÑкать в конÑоли базы данных, и они оч универÑальны
105# больше гуглите по SQL cheat sheet и документации к PostgreSQL
106# https://www.postgresql.org/docs/9.1/static/index.html
107# когда поработали Ñ conn, закройте его
108conn.close()
109
110# SQL очень удобный, но SQLAlchemy позволÑет оперировать объектами базы данных
111# ЧЕРЕЗ ОБЪЕКТЫ Python
112metadata = MetaData(engine)
113
114# подключимÑÑ Ðº таблице Ñ Ð´ÐµÑкрипторами
115#
116table_name = 'gwas_descriptors'
117schema = "test_schema"
118autoload = True # получить опиÑание из таблицы автоматичеÑки, а не пиÑать его Ñамому
119descriptors = Table(table_name, metadata, autoload = autoload, schema = schema)
120
121# так как мы передали объект metadata при ÑвÑзи, то можем поÑмотреть таблицы:
122metadata.tables.keys()
123#Result
124dict_keys(['test_schema.gwas_descriptors'])
125# metadata.tables возвращает dict Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ñ‹Ð¼ опиÑанием таблиц
126
127# поÑмотреть колонки в таблице
128list(descriptors.columns)
129
130# еÑли нужно выбрать данные
131selector = select([descriptors])
132list(conn.execute(selector))
133# Result
134[(1, '/home/storage/data/gwas_raw/FG/FG.txt', None, ,...),
135 (1, '/home/storage/data/gwas_raw/FG/FG.txt', None, ,...),
136 ...
137# нужно понимать, что Ñто проÑто обвÑзка над SQL запроÑами, и результат аналогичный курÑор из запроÑа:
138# SELECT test_schema.gwas_descriptors.gwas_id, ... FROM test_schema.gwas_descriptors
139
140# работать Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð°Ð¼Ð¸ можно через именованные Ñтолбцы
141# fetchone() вернёт первую запиÑÑŒ из результата. Ðапоминаю, что Ñледующий fetchone() вернет вторую, и так далее пока не будет выбрана поÑледнÑÑ
142result = conn.execute(selector)
143result.fetchone()["gwas_id"]
144# или аналогично pandas (descriptors.c возвращает колонки)
145result.fetchone()[descriptors.c.gwas_id]
146
147# выбрать
148selector = select([descriptors]).where(descriptors.c.gwas_id == 1)
149conn.execute(selector).fetchone()
150
151# добавить запиÑÑŒ
152# опиÑание ÑинтакÑиÑа insert Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹:
153ins = descriptors.insert()
154str(ins)
155# результат не очень понÑтный, так как много полей, общий ÑинтакÑÐ¸Ñ ÐºÐ°Ðº Ð´Ð»Ñ SQL
156# еÑть вариант опиÑывать полÑ
157ins = descriptors.insert().values(gwas_id=3, path='path/222', ...)
158# перед выполнением запроÑа хорошо поÑмотреть как он выглÑдит
159str(ins)
160
161# чтобы выполнить запроÑ, нужно передать его в conn.execute()
162conn.execute(ins)
163
164# аналогичные методы еÑть и Ð´Ð»Ñ update/delete
165# ПодробноÑти http://docs.sqlalchemy.org/en/latest/core/tutorial.html#inserts-updates-and-deletes
166
167# больше подробноÑтей:
168# http://docs.sqlalchemy.org/en/latest/core/tutorial.html