postgres查询中的循环法?

时间:2018-04-18 10:25:39

标签: sql postgresql

我目前有一些简单的表格:

检查

+----+--------+
| Id |  site  |
+----+--------+
|  1 | google |
|  2 | yahoo  |
|  3 | reddit |
+----+--------+

位置

+----+-----------+
| Id | location  |
+----+-----------+
|  1 | dallas    |
|  2 | singapore |
|  3 | london    |
+----+-----------+

checks_locations

+----------+-------------+
| check_id | location_id |
+----------+-------------+
|        1 |           1 |
|        1 |           2 |
|        1 |           3 |
|        2 |           2 |
|        2 |           3 |
|        3 |           3 |
+----------+-------------+

checks_requests

+----------+-------------+
| check_id | location_id |
+----------+-------------+
|        1 |           2 |
|        2 |           3 |
+----------+-------------+

我尝试做的是每次创建请求时遍历与每个站点关联的位置。基本上,我想根据最后一个请求,带回下一个位置ID的支票列表。

在这种情况下,那将是:

google, last location 2, next location 3  
yahoo, last location 3, next location 2 
reddit, last location nil, next location 3  

这是我的尝试:

select c.*, r.location_id as last_location, cl.location_id
from checks c
left outer join lateral (
  select * from requests r
  where c.id = r.check_id order by id desc limit 1
) r on true 
left outer join lateral (
  select * from checks_locations cl
  where c.id = cl.check_id and r.location_id != cl.location_id
  order by cl.location_id
) cl on true;

输出:

+----+--------+---------------+-------------+
| id |  site  | last_location | location_id |
+----+--------+---------------+-------------+
|  1 | google | 3             | 1           |
|  1 | google | 3             | 2           |
|  2 | yahoo  | 2             | 3           |
|  3 | reddit | null          | null        |
+----+--------+---------------+-------------+

正如你所看到的,我并不是那么接近,而且我完全失去了如何实现这一点,或者甚至是否可以使用PostgreSQL。我试图通过/ offset等将案例陈述整合到订单中,但它是一个巨大的混乱,我不能帮助,但认为有更好的方法。

以下是设置所有内容的数据库小提琴:https://www.db-fiddle.com/f/6fiK4gbkQMsV9yCm2c7qnk/3

1 个答案:

答案 0 :(得分:1)

尝试此解决方案:

SELECT ck.id,
       ck.site,
       rq.location_id AS last_location,
       CASE WHEN (rq.location_id IS NULL OR rq.location_id = (SELECT MAX(location_id)
                                                             FROM checks_locations clk
                                                             WHERE clk.check_id = ck.id))
                THEN MIN(cl.location_id)
            ELSE
                rq.location_id + 1
            END AS next_Location        
FROM checks ck
LEFT OUTER JOIN (SELECT check_id,
                        location_id
                        FROM requests
                        WHERE id IN (SELECT MAX(Id) 
                                     FROM requests
                                     GROUP BY check_id
                                     )
                ) AS rq
ON ck.id = rq.check_id 
LEFT JOIN checks_locations cl
ON ck.id = cl.check_id
GROUP BY ck.id,
       ck.site,
       rq.location_id;

<强>输出:

id |    site   | last_location | next_location
-----------------------------------------------
1  |    google |      3        |      1
2  |    quora  |      2        |      3
3  |    yahoo  |      null     |      3

链接到演示:

  

https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=bc88ccae2638a9f78f00912b9bb95539