Спецификация поиска c строк в SQL (вертикаль) - PullRequest
0 голосов
/ 03 марта 2020

У меня есть в основном одна таблица, но я создал другую (подмножество) таблицу из исходной. Я создам таблицу как Table 1, а таблицу подмножеств как Table 2.

Table_1 будет выглядеть так:

enter image description here

Table_2 выглядит так это:

enter image description here

Final_table должно выглядеть так:

enter image description here

Теперь, как вы можете видеть, Table_2 был создан путем выбора определенных текстов из Table_1. Теперь мне действительно нужен способ сначала найти те же самые строки данных в Table_1, а затем для каждой строки, оглядывающейся назад, используя дату (отметку времени), найти строку, когда value2 из Table_2 совпадает с текстом из Table_1. Всякий раз, когда это происходит, получите значение и добавьте его в столбец value_original. Таблица

Final показывает результат, который мне нужно получить. Как мне это сделать, используя Vertica sql?

Я попробовал этот код:

SELECT *
FROM
  (SELECT table_2.*, table_1.value as value_original
  FROM
      (Select * from table
      where date < '1/10/2020' 
      and text = 'settle') as table_2
  LEFT JOIN
      (Select * from table where date < '1/10/2020') as table_1
  ON table_2.id1 = table_1.id1 and table_2.id2 = table_1.id2 and table_2.value2 = table_1.text) as final_table
where value_original is not null
ORDER BY date

Я до сих пор не осознавал, насколько ужасным был мой выбор псевдонимов, извините за это , Попробовав этот код, я попал в ситуации, когда в Таблице_1 он будет иметь одни и те же значения несколько раз, но мне нужен тот, который находится ближе всего к выбранной строке в Таблице_2, возвращаясь назад с использованием даты (отметка времени). Я не уверен, как это сделать. Есть предложения?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 05 марта 2020

Вы работаете с Vertica, поэтому было бы законно использовать вещи, которые определены c для Vertica.

Мы работаем над временными рядами, здесь столбцы date и time задают темп.

Две особенности, которые вы увидите в приведенном ниже сценарии:

  • «Сеанс» - это функция CONDITIONAL_TRUE_EVENT() OLAP. Эта функция начинается с возврата 0 и возвращает число, увеличенное на 1 каждый раз, когда параметр логического выражения равен true, и сбрасывается в 0 каждый раз, когда изменяется выражение PARTITION BY. Я использую его, чтобы сгруппировать строки во все, что предшествует строке, чей txt является 'урегулированием'.
  • Analyti c Limit Clause - это LIMIT <n> OVER (PARTITION BY ... ORDER BY ...), который можно использовать для получить первую или последнюю строку во времени в группе.

Поэтому я запускаю полный выбор, чтобы получить идентификатор сеанса, и называю полный выбор w_sess, и я запускаю полный выбор из этого w_sess, чтобы получить последнюю строку в сеансе, чье txt является одним из трех предоставленных вами имен, и назовите его orig_rows, и, наконец, объедините два идентификатора сеанса, который я получил при сборке w_sess. Для ясности в сценарии я показываю в комментариях содержимое двух общих табличных выражений.

Приятной игры ...

WITH
input(id1,id2,txt,val,dt,tm) AS (
          SELECT 1,1,'jane'   ,97,DATE'2020-01-01','05:30:22'::TIME
UNION ALL SELECT 1,1,'henry'  ,54,DATE'2020-01-01','06:30:22'::TIME
UNION ALL SELECT 1,1,'jane'   ,10,DATE'2020-01-01','07:30:22'::TIME
UNION ALL SELECT 1,1,'jack'   , 2,DATE'2020-01-01','08:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,30,DATE'2020-01-01','09:30:22'::TIME
UNION ALL SELECT 1,1,'kara'   ,16,DATE'2020-01-01','10:30:22'::TIME
UNION ALL SELECT 1,1,'sam'    ,46,DATE'2020-07-01','11:30:22'::TIME
UNION ALL SELECT 1,1,'pam'    ,14,DATE'2020-07-01','12:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,27,DATE'2020-07-01','13:30:22'::TIME
UNION ALL SELECT 1,1,'michael',90,DATE'2020-07-01','14:30:22'::TIME
UNION ALL SELECT 1,1,'tom'    ,10,DATE'2020-07-01','15:30:22'::TIME
UNION ALL SELECT 1,1,'jackson',20,DATE'2020-07-01','16:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,40,DATE'2020-07-01','17:30:22'::TIME
)
,
w_sess AS (
SELECT
  CONDITIONAL_TRUE_EVENT(LAG(txt)='settle') OVER(
   PARTITION BY id1,id2 ORDER BY dt,tm
  ) AS session_id
, *
FROM input
)
-- select * from w_sess;
-- out  session_id | id1 | id2 |   txt   | val |     dt     |    tm    
-- out ------------+-----+-----+---------+-----+------------+----------
-- out           0 |   1 |   1 | jane    |  97 | 2020-01-01 | 05:30:22
-- out           0 |   1 |   1 | henry   |  54 | 2020-01-01 | 06:30:22
-- out           0 |   1 |   1 | jane    |  10 | 2020-01-01 | 07:30:22
-- out           0 |   1 |   1 | jack    |   2 | 2020-01-01 | 08:30:22
-- out           0 |   1 |   1 | settle  |  30 | 2020-01-01 | 09:30:22
-- out           1 |   1 |   1 | kara    |  16 | 2020-01-01 | 10:30:22
-- out           1 |   1 |   1 | sam     |  46 | 2020-07-01 | 11:30:22
-- out           1 |   1 |   1 | pam     |  14 | 2020-07-01 | 12:30:22
-- out           1 |   1 |   1 | settle  |  27 | 2020-07-01 | 13:30:22
-- out           2 |   1 |   1 | michael |  90 | 2020-07-01 | 14:30:22
-- out           2 |   1 |   1 | tom     |  10 | 2020-07-01 | 15:30:22
-- out           2 |   1 |   1 | jackson |  20 | 2020-07-01 | 16:30:22
-- out           2 |   1 |   1 | settle  |  40 | 2020-07-01 | 17:30:22
-- out (13 rows)
-- out 
-- out Time: First fetch (13 rows): 119.260 ms. All rows formatted: 119.315 ms
,
orig_rows AS (
SELECT
  *
FROM w_sess
WHERE txt IN('jane','pam','tom')
LIMIT 1 OVER(PARTITION BY session_id,txt ORDER BY dt DESC,tm DESC)
)
-- SELECT * FROM orig_rows;
-- out  session_id | id1 | id2 | txt  | val |     dt     |    tm    
-- out ------------+-----+-----+------+-----+------------+----------
-- out           0 |   1 |   1 | jane |  10 | 2020-01-01 | 07:30:22
-- out           1 |   1 |   1 | pam  |  14 | 2020-07-01 | 12:30:22
-- out           2 |   1 |   1 | tom  |  10 | 2020-07-01 | 15:30:22
-- out (3 rows)
-- out 
-- out Time: First fetch (3 rows): 211.165 ms. All rows formatted: 211.222 ms
 SELECT 
  w_sess.id1
, w_sess.id2
, w_sess.txt
, w_sess.val
, w_sess.dt
, orig_rows.txt AS value2
, orig_rows.val AS value_orig
FROM w_sess join orig_rows USING(session_id)
WHERE w_sess.txt='settle'
ORDER BY w_sess.session_id
;
-- out  id1 | id2 |  txt   | val |     dt     | value2 | value_orig 
-- out -----+-----+--------+-----+------------+--------+------------
-- out    1 |   1 | settle |  30 | 2020-01-01 | jane   |         10
-- out    1 |   1 | settle |  27 | 2020-07-01 | pam    |         14
-- out    1 |   1 | settle |  40 | 2020-07-01 | tom    |         10
-- out (3 rows)
-- out 
-- out Time: First fetch (3 rows): 540.519 ms. All rows formatted: 540.566 ms
0 голосов
/ 05 марта 2020

Просто подумал еще немного - и есть другой способ, также Vertica, указывающий c, чтобы решить вашу проблему.

Это еще один временной ряд, связанный с ie в СУБД: Event Series Join . Он работает со всеми внешними объединениями, объединяя текущую строку со строкой другой таблицы либо с совпадающим столбцом соединения (с предикатом INTERPOLATE PREVIOUS VALUE), либо со строкой с непосредственно предшествующим значением в столбце соединения.

Вы можете объединить несколько предикатов, но только один предикат может быть INTERPOLATE PREVIOUS VALUE.

В вашем случае, если возможно, что предыдущая строка, которую вы ищете, также имеет другую дату, а не только другое время, вы должны добавить столбец: ts TIMESTAMP DEFAULT dt+tm::INTERVAL в базовую таблицу, и INTERPOLATE PREVIOUS VALUE на этом.

Мой пример ленив и предполагает, что вы можете найти совпадение только по времени.

WITH
input(id1,id2,txt,val,dt,tm) AS (
          SELECT 1,1,'jane'   ,97,DATE'2020-01-01','05:30:22'::TIME
UNION ALL SELECT 1,1,'henry'  ,54,DATE'2020-01-01','06:30:22'::TIME
UNION ALL SELECT 1,1,'jane'   ,10,DATE'2020-01-01','07:30:22'::TIME
UNION ALL SELECT 1,1,'jack'   , 2,DATE'2020-01-01','08:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,30,DATE'2020-01-01','09:30:22'::TIME
UNION ALL SELECT 1,1,'kara'   ,16,DATE'2020-01-01','10:30:22'::TIME
UNION ALL SELECT 1,1,'sam'    ,46,DATE'2020-07-01','11:30:22'::TIME
UNION ALL SELECT 1,1,'pam'    ,14,DATE'2020-07-01','12:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,27,DATE'2020-07-01','13:30:22'::TIME
UNION ALL SELECT 1,1,'michael',90,DATE'2020-07-01','14:30:22'::TIME
UNION ALL SELECT 1,1,'tom'    ,10,DATE'2020-07-01','15:30:22'::TIME
UNION ALL SELECT 1,1,'jackson',20,DATE'2020-07-01','16:30:22'::TIME
UNION ALL SELECT 1,1,'settle' ,40,DATE'2020-07-01','17:30:22'::TIME
)
,
orig_rows AS (
SELECT 
  *
FROM input
WHERE txt IN('jane','pam','tom')
)
SELECT
  input.id1
, input.id2
, input.txt
, input.val
, input.dt
, input.dt + input.tm::interval AS ts
, orig_rows.txt AS value2
, orig_rows.val AS value_orig
FROM input
LEFT JOIN orig_rows
 ON input.id1=orig_rows.id1
AND input.id2=orig_rows.id2
AND input.dt = orig_rows.dt
AND input.tm INTERPOLATE PREVIOUS VALUE orig_rows.tm
WHERE input.txt='settle'
;
-- out  id1 | id2 |  txt   | val |     dt     |         ts          | value2 | value_orig 
-- out -----+-----+--------+-----+------------+---------------------+--------+------------
-- out    1 |   1 | settle |  30 | 2020-01-01 | 2020-01-01 09:30:22 | jane   |         10
-- out    1 |   1 | settle |  27 | 2020-07-01 | 2020-07-01 13:30:22 | pam    |         14
-- out    1 |   1 | settle |  40 | 2020-07-01 | 2020-07-01 17:30:22 | tom    |         10
-- out (3 rows)
-- out 
-- out Time: First fetch (3 rows): 90.260 ms. All rows formatted: 90.301 ms

счастливая игра, снова ...

0 голосов
/ 03 марта 2020

Я думаю, вы просто хотите left join:

select t2.*, t1.value as value_orig
from table_2 t2 left join
     table_1 t1
     on t2.id1 = t1.id1 and
        t2.id2 = t1.id2 and
        t2.value2 = t1.text;
...