Как передать параметр Python из config.py в файл .sql?

Я использую коннектор Python Snowflake для извлечения данных из таблиц в Snowflake. Вот моя файловая структура:

sql
   a.sql
   b.sql
   c.sql
configurations.py
data_extract.py
main.py

Здесь папка sql содержит все мои запросы sql в файлах .sql. Я помещаю эти файлы sql отдельно, потому что каждый из них состоит из длинных строк и выглядит беспорядочно, если я помещаю их в файлы python. configuration.py содержит параметры даты и времени, которые я хочу изменять каждый раз при запуске кода. Это выглядит так:

START_TIME = '2018-10-01 00:00:00'
END_TIME = '2019-04-01 00:00:00'

Я хочу добавить эти параметры в файлы .sql. Например, a.sql включает следующее содержимое:

DECLARE
  @START_PICKUP_DATE DATE,
  @END_PICKUP_DATE DATE,

SET
  @START_PICKUP_DATE = '2018-10-01'

SET
  @END_PICKUP_DATE = '2019-04-01'

select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= START_PICKUP_DATE and pickup_datetime < END_PICKUP_DATE
      and supplier_confirmation_id is not null;

Я использую a.sql в своем коде на Python следующим образом:

def executeSQLScriptsFromFile(filepath):
    # snowflake credentials, replace SECRET with your own
    ctx = snowflake.connector.connect(
        user='S_ANALYTICS_USER',
        account=SECRET_A,
        region='us-east-1',
        warehouse=SECRET_B,
        database=SECRET_C,
        role=SECRET_D,
        password=SECRET_E)

    fd = open(filepath, 'r')
    query = fd.read()
    fd.close()

    cs = ctx.cursor()
    try:
        cur = cs.execute(query)
        df = pd.DataFrame.from_records(iter(cur), columns=[x[0] for x in cur.description])
    finally:
        cs.close()
    ctx.close()

    return df

def extract_data():
    a_sqlpath = os.path.join(os.getcwd(), 'sql\a.sql')
    a_df = executeSQLScriptsFromFile(a_sqlpath)
    return a_df

Проблема в том, что я хочу, чтобы START_PICKUP_DATE и END_PICKUP_DATE в файле a.sql были синхронизированы и равны START_TIME и END_TIME в файле configurations.py, чтобы мне нужно было только изменить START_TIME и END_TIME в configurations.py и извлечь данные в другой период времени. используя a.sql в Snowflake.

Я довольно долго искал решения в Интернете, но до сих пор не могу найти хорошее решение, специфичное для моей проблемы. Большое спасибо всем, кто может дать подсказку!


person CathyQian    schedule 12.08.2019    source источник


Ответы (2)


Вы должны иметь возможность параметризовать операторы sql, чтобы вместо объявления в файле SQL вы могли просто сделать его параметром, передаваемым во время выполнения.

select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= %(START_PICKUP_DATE)s and pickup_datetime < %(END_PICKUP_DATE)s and supplier_confirmation_id is not null;

Затем при вызове функции просто отправьте параметры START_PICKUP_DATE и END_PICKUP_DATE в качестве параметров в оператор выполнения. Один из способов сделать это - выполнить сопоставление имени параметра со значением параметра. (В этом примере я предполагаю, что у вас есть функция, которая получает значение параметра).

cur = cs.execute(query, {'START_PICKUP_DATE':get_value_from_config('start_pickup'), 'END_PICKUP_DATE':get_value_from_config('end_pickup')})

Или вы можете передать их по местоположению

cur = cs.execute(query, [get_value_from_config('start_pickup'), get_value_from_config('end_pickup')])

Что по сути становится

cur = cs.execute(query, ['2018-10-01 00:00:00','2019-04-01 00:00:00'])
person MichaelD    schedule 12.08.2019
comment
@MichaeID Спасибо за предложение! Что делать, если имя параметра в configurations.py и в a.sql не совсем то же самое? - person CathyQian; 12.08.2019
comment
@MichaelID, Кстати, у вас есть документация, на которую я могу сослаться? Например, как я могу активировать get_value_from_config ()? - person CathyQian; 12.08.2019
comment
Я просто использовал придуманную функцию get_value_from_config, которую вы можете создать. Ничего особенного в этом нет. Ключ в том, что вы передаете параметры как часть оператора execute. Я дополню ответ более подробной информацией - person MichaelD; 12.08.2019
comment
Спасибо! Незначительная модификация путем добавления 's' после '% (param_name)', заканчивающегося на '% (param_name) s'. См. Ниже: select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance from SANDBOX.ZQIAN.V_PDL where pickup_datetime >= %(START_PICKUP_DATE)s and pickup_datetime < %(END_PICKUP_DATE)s and supplier_confirmation_id is not null; - person CathyQian; 12.08.2019
comment
@MichaeID, я попробовал метод, который вы предоставили, и он работает хорошо, за исключением одного случая, когда он продолжает выдавать мне следующую ошибку: query = command % processed_params TypeError: not enough arguments for format string Кажется, cs.execute(query, param_dict) каким-то образом не распознает параметры. Единственное различие, которое я заметил, заключается в том, что я использовал «With» в моем запросе sql, а параметры находятся в дочерних запросах. Есть мысли? - person CathyQian; 12.08.2019

Для этого я возьму ваши файлы .sql и извлечу запросы в строки Python с тройными кавычками со спецификаторами формата для ваших переменных. Затем импортируйте запросы в свой основной скрипт так же, как вы импортируете свою конфигурацию:

sql_queries.py:

sql_a = """
DECLARE
  @START_PICKUP_DATE DATE,
  @END_PICKUP_DATE DATE,

SET
  @START_PICKUP_DATE = {START_TIME}

SET
  @END_PICKUP_DATE = {END_TIME}

select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= START_PICKUP_DATE and pickup_datetime < END_PICKUP_DATE
  and supplier_confirmation_id is not null;
"""

main:
from sql_queries import sql_a

print(sql_a.format(configuration.START_TIME, configuration.END_TIME))
person mgrollins    schedule 12.08.2019