Создайте клейкую ленту из одинарных и двойных кавычек - PullRequest
0 голосов
/ 07 мая 2020

Я пытаюсь создать строку, используя пакет glue в R, который представляет собой смесь 'одинарных' и «двойных» кавычек.

В качестве представления рассмотрим следующий тип SQL строки запроса, которую я хочу построить:

CREATE TABLE fact_final_table AS 
(SELECT tab1.id,
    AVG(tab2."MV") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '7'
                                                      AND tab1.start_date::date - integer '1') AS "mv_avg_1w",
    AVG(tab2."MV") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '14'
                                                      AND tab1.start_date::date - integer '1') AS "mv_avg_2w"
FROM (SELECT id,
             start_date,
             point
      FROM base_tab
      WHERE mpfb.start_date::date >= '01-01-2000'::date) AS tab1
LEFT JOIN ghcnd_observations AS tab2
    ON (tab2.record_dt BETWEEN (tab1.start_date::date - integer '180')
                           AND (tab1.start_date::date - integer '1')
        AND ST_DWithin(tab1.point, tab2.location, 0.5))
GROUP BY tab1.id);

Как видите, это комбинация одинарных и двойных кавычек, которые важно сохранить буквально как написано выше. Например, tab2."MV" имеет двойные кавычки, а tab1.start_date::date - integer '7' AND tab1.start_date::date - integer '1' - одинарные кавычки, которые необходимо сохранять буквально.

Эта строка также должна быть построена с использованием параметров. Я пробовал следующее в R, используя glue, но не смог заставить его работать.

var1       <- "MV"
var1_lowcase <- "mv"
lag_days   <- 180
var_date   <- as.Date("2000-01-01")
var_dwithin <- 0.5

glue::glue(
"CREATE TABLE fact_final_table AS 
(SELECT tab1.id,
    AVG(tab2."{var1}") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '7'
                           AND tab1.start_date::date - integer '1') AS "{var1_lowcase}_avg_1w",
    AVG(tab2."{var1}") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '14'
                           AND tab1.start_date::date - integer '1') AS "{var1_lowcase}_avg_2w"
    FROM (SELECT id,
          start_date,
          point
          FROM base_tab
          WHERE mpfb.start_date::date >= '{format(var_date, "%d-%m-%Y")}'::date) AS tab1
    LEFT JOIN ghcnd_observations AS tab2
    ON (tab2.record_dt BETWEEN (tab1.start_date::date - integer '{lag_days}')
        AND (tab1.start_date::date - integer '1')
        AND ST_DWithin(tab1.point, tab2.location, {var_dwithin}))
    GROUP BY tab1.id);")

К сожалению, это не работает из-за неправильного экранирования одинарных / двойных кавычек в glue::glue(...) .

Может ли кто-нибудь помочь здесь с минимальным нарушением требуемой выходной строки? Я не уверен, легко ли это осуществимо. Я был бы признателен за любые другие подходы tidy, например, используя stringr, так как я хотел бы, чтобы это было %>% дружелюбным. Я вкратце посмотрел на glue::glue_sql, но не знал, как применить его здесь напрямую. Буду признателен, если узнаю, как его использовать здесь, где это возможно.

Ответы [ 2 ]

0 голосов
/ 07 мая 2020

Итак, я изучал это более подробно со вчерашнего дня, и оказалось, что glue действительно имеет функции для явного создания одинарных и двойных кавычек т.е. glue::single_quote() и glue::double_quote().

Подобно (полезному) ответу @ronakshah, мне удалось сделать следующее, более явное (для читабельности кода):

var1       <- "MV"
var1_lowcase <- "mv"
lag_days   <- 180
var_date   <- as.Date("2000-01-01")
var_dwithin <- 0.5

glue::glue(
    "CREATE TABLE fact_final_table AS 
   (SELECT tab1.id,
   AVG(tab2.{glue::double_quote(var1)}) FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '7'
   AND tab1.start_date::date - integer '1') AS {glue::double_quote(glue::glue({var1_lowcase},'_avg_1w'))},
   AVG(tab2.{glue::double_quote(var1)}) FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '14'
   AND tab1.start_date::date - integer '1') AS {glue::double_quote(glue::glue({var1_lowcase},'_avg_2w'))}
   FROM (SELECT id,
         start_date,
          point
   FROM base_tab
    WHERE mpfb.start_date::date >= {glue::single_quote(format(var_date, '%d-%m-%Y'))}::date) 
  AS tab1
   LEFT JOIN ghcnd_observations AS tab2
   ON (tab2.record_dt BETWEEN (tab1.start_date::date - integer '{lag_days}')
   AND (tab1.start_date::date - integer '1')
   AND ST_DWithin(tab1.point, tab2.location, {var_dwithin}))
   GROUP BY tab1.id);")

Возвращает основную строку, которую я требовал. Надеюсь, это поможет другим, у кого были похожие требования glue.

0 голосов
/ 07 мая 2020

Попробуйте избежать двойных кавычек:

glue::glue(
   "CREATE TABLE fact_final_table AS 
   (SELECT tab1.id,
   AVG(tab2.\"{var1}\") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '7'
   AND tab1.start_date::date - integer '1') AS \"{var1_lowcase}_avg_1w\",
   AVG(tab2.\"{var1}\") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date - integer '14'
   AND tab1.start_date::date - integer '1') AS \"{var1_lowcase}_avg_2w\"
   FROM (SELECT id,
         start_date,
          point
   FROM base_tab
    WHERE mpfb.start_date::date >= '{format(var_date, \"%d-%m-%Y\")}'::date) 
  AS tab1
   LEFT JOIN ghcnd_observations AS tab2
   ON (tab2.record_dt BETWEEN (tab1.start_date::date - integer '{lag_days}')
   AND (tab1.start_date::date - integer '1')
   AND ST_DWithin(tab1.point, tab2.location, {var_dwithin}))
   GROUP BY tab1.id);")

, что возвращает:

#CREATE TABLE fact_final_table AS 
#(SELECT tab1.id,
#AVG(tab2."MV") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date #- integer '7'
#AND tab1.start_date::date - integer '1') AS "mv_avg_1w",
#AVG(tab2."MV") FILTER (WHERE tab2.record_dt BETWEEN tab1.start_date::date #- integer '14'
#AND tab1.start_date::date - integer '1') AS "mv_avg_2w"
#FROM (SELECT id,
#start_date,
#point
#FROM base_tab
#WHERE mpfb.start_date::date >= '01-01-2000'::date) AS tab1
#LEFT JOIN ghcnd_observations AS tab2
#ON (tab2.record_dt BETWEEN (tab1.start_date::date - integer '180')
#AND (tab1.start_date::date - integer '1')
#AND ST_DWithin(tab1.point, tab2.location, 0.5))
#GROUP BY tab1.id);
...