Как я могу запросить базу данных со списком значений? - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть база данных координат широты / долготы каждого крупного аэропорта по всему миру. Мне нужна только часть из них (особенно в США), которые перечислены в отдельном файле .csv.

Этот CSV-файл содержит две колонки, из которых я извлек данные в два списка: код аэропорта отправителя (код IATA) и код аэропорта назначения (также IATA).

В моей базе данных есть столбец для IATA, и, по сути, я пытаюсь выполнить запрос к этой базе данных, чтобы получить соответствующие координаты широты / долготы для каждого аэропорта в двух списках, которые у меня есть.

Вот мой код:

import pandas as pd
from sqlalchemy import create_engine

engine = create_engine('sqlite:///airport_coordinates.db')

# The dataframe that contains the IATA codes for the airports I need
airport_relpath = "data/processed/%s_%s_combined.csv" % (file, airline)
script_dir = os.path.dirname(os.getcwd())
temp_file = os.path.join(script_dir, airport_relpath)
fields = ["Origin_Airport_Code", "Destination_Airport_Code"]
df_airports = pd.read_csv(temp_file, usecols=fields)

# the origin/destination IATA codes for the airports I need
origin = df_airports.Origin_Airport_Code.values
dest = df_airports.Destination_Airport_Code.values

# query the database for the lat/long coords of the airports I need
sql = ('SELECT lat, long FROM airportCoords WHERE iata IN %s' %(origin))
indexcols = ['lat', 'long']

df_origin = pd.read_sql(sql, engine)
# testing the origin coordinates
print(df_origin)

Это ошибка, которую я получаю:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such 
table: 'JFK' 'JFK' 'JFK' ... 'MIA' 'JFK' 'MIA' [SQL: "SELECT lat, long 
FROM airportCoords WHERE iata IN ['JFK' 'JFK' 'JFK' ... 'MIA' 'JFK' 
'MIA']"] (Background on this error at: http://sqlalche.me/e/e3q8)

Это определенно потому, что я не правильно его запрашиваю (так как он думает, что мои запросы должны быть к таблицам).

Я попытался пройтись по списку, чтобы запросить каждый элемент в отдельности, но список содержит более 604 885 элементов, и мой компьютер не смог выдать какой-либо вывод.

1 Ответ

0 голосов
/ 13 ноября 2018

Ваша ошибка в использовании интерполяции строк:

sql = ('SELECT lat, long FROM airportCoords WHERE iata IN %s' %(origin))

Поскольку origin является массивом Numpy, это приводит к синтаксису [....] идентификатора SQL в запросе;см. документацию по SQLite :

Если вы хотите использовать ключевое слово в качестве имени, вам нужно заключить его в кавычки.Существует четыре способа цитирования ключевых слов в SQLite:

[...]
[keyword] Ключевое слово, заключенное в квадратные скобки, является идентификатором.[...]

Вы попросили SQLite проверить, находится ли iata в таблице с именем ['JFK' 'JFK' 'JFK' ... 'MIA' 'JFK' 'MIA'], потому что это строковое представление массива Numpy.

Вы ужеиспользуя SQLAlchemy, было бы проще, если бы вы использовали эту библиотеку для генерации всего SQL для вас, включая тест членства IN (....):

from sqlalchemy import *

filter = literal_column('iata', String).in_(origin)
sql = select([
    literal_column('lat', Float),
    literal_column('long', Float),
]).select_from(table('airportCoords')).where(filter)

и затем sql в качестве запроса.

Я использовал здесь literal_column() и table() объекты для быстрого доступа к именам объектов, но вы также можете попросить SQLAlchemy отразить вашу таблицу базы данных непосредственно из объекта engine, который вы уже создализатем используйте полученное определение таблицы, чтобы сгенерировать запрос:

metadata = MetaData()
airport_coords = Table('airportCoords', metadata, autoload=True, autoload_with=engine)

, в этот момент запрос будет определен как:

filter = airport_coords.c.iata.in_(origin)
sql = select([airport_coords.c.lat, airport_coords.c.long]).where(filter)

Я бы также включил код iataв выходных данных, в противном случае у вас не будет пути к подключению кода IATA к соответствующим координатам:

sql = select([airport_coords.c.lat, airport_coords.c.long, airport_coords.c.iata]).where(filter)

Далее, как вы говорите, в списке 604 885 элементов, поэтому вы , вероятно, хочу загрузить данные CSVa во временную таблицу для обеспечения эффективности запроса:

engine = create_engine('sqlite:///airport_coordinates.db')

# code to read CSV file
# ...
df_airports = pd.read_csv(temp_file, usecols=fields)

# SQLAlchemy table wrangling
metadata = MetaData()
airport_coords = Table('airportCoords', metadata, autoload=True, autoload_with=engine)
temp = Table(
    "airports_temp",
    metadata,
    *(Column(field, String) for field in fields),
    prefixes=['TEMPORARY']
)
with engine.begin() as conn:
    # insert CSV values into a temporary table in SQLite
    temp.create(conn, checkfirst=True)
    df_airports.to_sql(temp.name), engine, if_exists='append')

# Join the airport coords against the temporary table
joined = airport_coords.join(temp, airport_coords.c.iata==temp.c.Origin_Airport_Code)

# select coordinates per airport, include the iata code
sql = select([airport_coords.c.lat, airport_coords.c.long, airport_coords.c.iata]).select_from(joined)
df_origin = pd.read_sql(sql, engine)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...