2017-02-11 1 views
1

Я, имеющим две таблицы, в которых table1Как я могу получить разницу ближайших два дня в два таблице присоединиться к PostgreSQL

 activity_timestamp | activity 
          |  
2016-12-23 13:53:47.608561| details viewed 
2017-01-09 14:15:52.570397| details viewed 
2016-12-27 16:06:39.138994| details viewed 
2016-12-24 21:09:56.159436| details viewed 

table2

 activity_timestamp | activity 
          |  
2016-12-23 13:54:47.608561| reading 
2017-01-09 14:17:52.570397| reading 
2016-12-27 16:10:39.138994| reading 
2016-12-24 21:012:56.159436| reading 

Я должен рассчитать время между этими двумя видами активности и считыванием деталей Таблица результатов

timediff (minutes) 

     1 
     2 
     4 
     3 

Эти две таблицы я должен сделать присоединиться на эти таблицы с условием разница между двумя activity_timestamp тогда только что запись будет добавлена ​​в итоговой таблице для этого менее 20 мин я прописан этот запрос,

select DATE_PART('minutes', a1.activity_timestamp- b.activity_timestamp), 
    a1.activity_timestamp, b.activity_timestamp 
from table a1 LEFT JOIN table2 b 
    ON(DATE_PART('minutes', (a1.activity_timestamp - b.activity_timestamp))< 20 
     and (a1.activity_timestamp>b.activity_timestamp)) 
order by b.activity_timestamp;  

Но я получаю результат, который, как представляется, неоднозначное , что я могу сделать, чтобы получить присоединиться, который вернет меня больше рекорд, который имея только 20 мин разность

+1

Если у вас есть только метки времени, у вас не может быть «записи», так как может быть неограниченное количество записей. Пожалуйста, добавьте объяснение результата, который вы хотите получить, и результат, который вам известен. –

+0

Является ли деятельность всегда после b-активности? –

+0

да в первой таблице их записи будут на 5-10 минут раньше второй записи –

ответ

0

Просто используйте прямые сравнения дат в пункте on , а не минуты разницы:

select date_part('minutes', a1.activity_timestamp - b.activity_timestamp), 
     a1.activity_timestamp, b.activity_timestamp 
from table a1 left join 
    table2 b 
    on a.active_timestamp < b.activity_timestamp + interval '20 minute' and 
     a.activity_timetamp > b.activity_timestamp 
order by b.activity_timestamp; 

следует отметить: Если (в случае нескольких матчей) вы хотите ограничить это только одна запись из a или b, то вы можете использовать distinct on. Однако я не уверен, какая таблица вам нужна только для одной записи.

+0

Я хочу присоединиться к первой таблице –

1
with 
    table1(activity_timestamp, activity) as (
    values 
     ('2016-12-23 13:53:47.608561'::timestamp, 'details viewed'), 
     ('2017-01-09 14:15:52.570397', 'details viewed'), 
     ('2016-12-27 16:06:39.138994', 'details viewed'), 
     ('2016-12-24 21:09:56.159436', 'details viewed')), 
    table2(activity_timestamp, activity) as (
    values 
     ('2016-12-23 13:54:47.608561'::timestamp, 'reading'), 
     ('2017-01-09 14:17:52.570397', 'reading'), 
     ('2016-12-27 16:10:39.138994', 'reading'), 
     ('2016-12-24 21:012:56.159436', 'reading')) 
select 
    *, 
    activity_timestamp - (select max(activity_timestamp) from table1 as t1 where t2.activity_timestamp > t1.activity_timestamp) as diff 
from table2 as t2 order by activity_timestamp, activity; 
 
╔════════════════════════════╤══════════╤══════════╗ 
║  activity_timestamp  │ activity │ diff ║ 
╠════════════════════════════╪══════════╪══════════╣ 
║ 2016-12-23 13:54:47.608561 │ reading │ 00:01:00 ║ 
║ 2016-12-24 21:12:56.159436 │ reading │ 00:03:00 ║ 
║ 2016-12-27 16:10:39.138994 │ reading │ 00:04:00 ║ 
║ 2017-01-09 14:17:52.570397 │ reading │ 00:02:00 ║ 
╚════════════════════════════╧══════════╧══════════╝ 

Но я не уверен, что нужные строки заказа ...

+0

, когда я был добавлен условие только для записи, которая находится между 20 минутами, следует вычесть этот запрос me output in days –

+0

@AbhijeetGulve Используйте ['extract ('epoch' from interval)' function] (https://www.postgresql.org/docs/current/static/functions-datetime.html), чтобы получить количество секунд , http://rextester.com/GZS98586 – Abelisto

+0

спасибо, теперь работает для меня. –

1

Я предлагаю использовать Windowing функции:

with 
    table1(activity_timestamp, activity) as (
    values 
     ('2016-12-23 13:53:47.608561'::timestamp, 'details viewed'), 
     ('2017-01-09 14:15:52.570397', 'details viewed'), 
     ('2016-12-27 16:06:39.138994', 'details viewed'), 
     ('2016-12-24 21:09:56.159436', 'details viewed')), 
    table2(activity_timestamp, activity) as (
    values 
     ('2016-12-23 13:54:47.608561'::timestamp, 'reading'), 
     ('2017-01-09 14:17:52.570397', 'reading'), 
     ('2016-12-27 16:10:39.138994', 'reading'), 
     ('2016-12-24 21:012:56.159436', 'reading')) 
    , lag AS (
select 
    *, lag(activity_timestamp) OVER (ORDER BY activity_timestamp) 
from (
    SELECT * FROM table1 
    UNION SELECT * FROM table2 
) AS a 

) SELECT *, lag - activity_timestamp 
FROM lag 
WHERE activity = 'reading' 
ORDER BY 1 
; 

Результаты является:

activity_timestamp  | activity |   lag    | ?column? 
----------------------------+----------+----------------------------+----------- 
2016-12-23 13:54:47.608561 | reading | 2016-12-23 13:53:47.608561 | -00:01:00 
2016-12-24 21:12:56.159436 | reading | 2016-12-24 21:09:56.159436 | -00:03:00 
2016-12-27 16:10:39.138994 | reading | 2016-12-27 16:06:39.138994 | -00:04:00 
2017-01-09 14:17:52.570397 | reading | 2017-01-09 14:15:52.570397 | -00:02:00 
(4 rows) 

Для сравнения с другой предлагаемой версией i cre ели следующий сценарий:

CREATE TABLE table1 AS 
SELECT '2016-01-01'::timestamp + '1 min'::interval * (random() * 10 + 1) AS activity_timestamp, 
     'dv'::text AS activity 
FROM generate_series(1, 100000); 

CREATE TABLE table2 AS 
SELECT activity_timestamp + '1 min'::interval * (random()) AS activity_timestamp, 
     'r'::text AS activity 
    FROM table1; 

CREATE INDEX i1 ON table1 (activity_timestamp DESC); 
CREATE INDEX i2 ON table2 (activity_timestamp DESC); 

-- Proposed by Abelisto 
explain analyze 
select 
    *, 
    activity_timestamp - (select max(activity_timestamp) 
          from table1 as t1 
         where t2.activity_timestamp > t1.activity_timestamp 
) as diff 
from table2 as t2 order by activity_timestamp, activity; 


-- Gordon Linoff - repaired  
explain analyze 
select date_part('minutes', a.activity_timestamp - b.activity_timestamp), 
     a.activity_timestamp, b.activity_timestamp 
from table1 a left join 
    table2 b 
    on a.activity_timestamp < b.activity_timestamp + interval '20 minute' and 
     a.activity_timestamp > b.activity_timestamp 
order by b.activity_timestamp; 

-- My own version 
explain analyze 
WITH lag AS (
select 
    *, lag(activity_timestamp) OVER (ORDER BY activity_timestamp) 
from (
    SELECT * FROM table1 
    UNION SELECT * FROM table2 
) AS a 

) SELECT *, lag - activity_timestamp 
FROM lag 
WHERE activity = 'reading' 
ORDER BY 1; 

Для запроса по Гордон время запроса слишком долго (я не хочу ждать). Abelisto:

                 QUERY PLAN                   
----------------------------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=53399.41..53649.41 rows=100000 width=56) (actual time=944.918..957.470 rows=100000 loops=1) 
    Sort Key: t2.activity_timestamp, t2.activity 
    Sort Method: external merge Disk: 4104kB 
    -> Seq Scan on table2 t2 (cost=0.00..41675.09 rows=100000 width=56) (actual time=0.068..874.282 rows=100000 loops=1) 
     SubPlan 2 
      -> Result (cost=0.39..0.40 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=100000) 
       InitPlan 1 (returns $1) 
        -> Limit (cost=0.29..0.39 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=100000) 
         -> Index Only Scan using i1 on table1 t1 (cost=0.29..3195.63 rows=33167 width=8) (actual time=0.008..0.008 rows=1 loops=100000) 
           Index Cond: ((activity_timestamp IS NOT NULL) AND (activity_timestamp < t2.activity_timestamp)) 
           Heap Fetches: 100000 
Planning time: 0.392 ms 
Execution time: 961.594 ms 
(13 rows) 

Мой собственный:

                QUERY PLAN                 
---------------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=39214.47..39216.97 rows=1000 width=64) (actual time=325.461..325.461 rows=0 loops=1) 
    Sort Key: lag.activity_timestamp 
    Sort Method: quicksort Memory: 25kB 
    CTE lag 
    -> WindowAgg (cost=28162.14..34662.14 rows=200000 width=48) (actual time=131.906..265.747 rows=199982 loops=1) 
      -> Unique (cost=28162.14..29662.14 rows=200000 width=40) (actual time=131.900..200.937 rows=199982 loops=1) 
       -> Sort (cost=28162.14..28662.14 rows=200000 width=40) (actual time=131.899..167.072 rows=200000 loops=1) 
         Sort Key: table1.activity_timestamp, table1.activity 
         Sort Method: external merge Disk: 4000kB 
         -> Append (cost=0.00..5082.00 rows=200000 width=40) (actual time=0.007..27.569 rows=200000 loops=1) 
          -> Seq Scan on table1 (cost=0.00..1541.00 rows=100000 width=40) (actual time=0.007..8.584 rows=100000 loops=1) 
          -> Seq Scan on table2 (cost=0.00..1541.00 rows=100000 width=40) (actual time=0.007..7.248 rows=100000 loops=1) 
    -> CTE Scan on lag (cost=0.00..4502.50 rows=1000 width=64) (actual time=325.458..325.458 rows=0 loops=1) 
     Filter: (activity = 'reading'::text) 
     Rows Removed by Filter: 199982 
Planning time: 0.103 ms 
Execution time: 327.737 ms 
(17 rows) 

Для сравнения я также запускать все запросы на 1000 строк: Abelisto:

                 QUERY PLAN                  
----------------------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=469.71..472.21 rows=1000 width=56) (actual time=8.817..8.882 rows=1000 loops=1) 
    Sort Key: t2.activity_timestamp, t2.activity 
    Sort Method: quicksort Memory: 103kB 
    -> Seq Scan on table2 t2 (cost=0.00..419.89 rows=1000 width=56) (actual time=0.058..8.441 rows=1000 loops=1) 
     SubPlan 2 
      -> Result (cost=0.39..0.40 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=1000) 
       InitPlan 1 (returns $1) 
        -> Limit (cost=0.28..0.39 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=1000) 
         -> Index Only Scan using i1 on table1 t1 (cost=0.28..38.91 rows=332 width=8) (actual time=0.007..0.007 rows=1 loops=1000) 
           Index Cond: ((activity_timestamp IS NOT NULL) AND (activity_timestamp < t2.activity_timestamp)) 
           Heap Fetches: 1000 
Planning time: 0.311 ms 
Execution time: 8.948 ms 
(13 rows) 

Гордон:

               QUERY PLAN                
------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=21087.07..21364.85 rows=111111 width=24) (actual time=439.142..528.240 rows=452961 loops=1) 
    Sort Key: b.activity_timestamp 
    Sort Method: external merge Disk: 15016kB 
    -> Nested Loop Left Join (cost=0.28..9493.05 rows=111111 width=24) (actual time=0.056..280.036 rows=452961 loops=1) 
     -> Seq Scan on table1 a (cost=0.00..16.00 rows=1000 width=8) (actual time=0.007..0.114 rows=1000 loops=1) 
     -> Index Only Scan using i2 on table2 b (cost=0.28..7.81 rows=111 width=8) (actual time=0.006..0.171 rows=453 loops=1000) 
       Index Cond: (activity_timestamp < a.activity_timestamp) 
       Filter: (a.activity_timestamp < (activity_timestamp + '00:20:00'::interval)) 
       Heap Fetches: 452952 
Planning time: 0.102 ms 
Execution time: 545.139 ms 
(11 rows) 

Мой собственный:

+0

Помог ли мой ответ? –