在postgresql中按查询分组

时间:2014-03-27 11:51:08

标签: postgresql

我有2张桌子

表1:

id | user_id  | pattern
1  |   3      | ^1212.*
2  |   3      | ^192.*
3  |   4      | ^20.*

表2:

id |pattern | start_date          | comment
1  |^1212.* | 2014-03-22 20:10:13 | India-Gujarat
2  |^1212.* | 2014-03-24 20:10:13 | India -Maharastra
3  |^1212.* | 2014-03-25 20:10:13 | India -uttar pradesh
4  |^1212.* | 2014-03-27 20:10:13 | India -Madhya pradesh
5  |^1212.* | 2014-03-29 20:10:13 | India -Rajasthan
6  |^192.* | 2014-03-22 20:10:13  | Africa
7  |^20.* | 2014-03-22 20:10:13   | Indonesia- first
8  |^20.* | 2014-03-26 20:10:13   | indonesia -second
9  |^1212.* | 2014-03-22 20:10:13 | India- kerala
10 |^13.* | 2014-03-22 20:10:13   | Usa
11 |^13.* | 2014-03-22 20:12:13   | usa
12 |^14.* | 2014-03-22 20:10:13   | U.k

必填项:

id | pattern | start_date
8  |^20.* | 2014-03-26 20:10:13 | Indonesia-first
10 | ^13.*  | 2014-03-22 20:12:13 | USA
12 | ^14.*  | 2014-03-22 20:10:13 | U.k

输出要求:

  1. 基于user_id = {current user},表1中不存在模式 在这里我们可以看到user_id有1212,92,20但是它没有在表1中有20,13,14模式
  2. 表2中显示的模式及其注释以及start_date必须最接近当前时间
  3. 模式必须是明确的
  4. 我尝试使用3次执行查询的PHP代码,需要很长时间

    1. 按照模式
    2. 从table2 group中选择distinct(pattern)
    3. 从table1中选择*,其中user_id = login_id
    4. php中的foreach循环(从table2中选择*,其中id不在(query2的输出)和模式(' 123'))
    5. 所以可以在postgresql中使用单个查询

1 个答案:

答案 0 :(得分:0)

这应该可以解决问题:

SELECT DISTINCT a.pattern
FROM table2 a
LEFT OUTER JOIN table1 b ON a.pattern = b.pattern AND b.user_id = {current_user}
WHERE b.id IS NULL

将表2中的所有行与表1中的所有行连接起来,基于它们的模式,并且只有它属于当前用户。然后你只选择那些无法连接的那些。

更新

根据您的评论,我不再100%确定您的意思。一种方法是将DISTINCT添加到上面的查询中。

另一种变体是

SELECT DISTINCT pattern FROM table2
EXCEPT
SELECT pattern FROM table1 WHERE user_id = {current user}

更新2

根据您想要来自表2最新一行的其他信息的信息,此查询可能会对您有所帮助:

SELECT a.* FROM table2 a
INNER JOIN (
  SELECT pattern, MAX(start_date) AS max_start_date
  FROM table2
  GROUP BY pattern
) mostrecent
ON a.pattern = mostrecent.pattern AND a.start_date = mostrecent.max_start_date
LEFT OUTER JOIN table1 b ON a.pattern = b.pattern AND b.user_id = {current_user}
WHERE b.id IS NULL

上半部分请求table2中所有最近的行。下半部分(以LEFT OUTER JOIN开头)将此连接到表1,并且(如前所述)仅选择那些在table1中没有行的行。

另一个专门用于Postgresql 8.4+的解决方案是

WITH mostrecent AS (
  SELECT *,
    ROW_NUMBER() OVER(PARTITION BY pattern ORDER BY start_date DESC) AS rank
  FROM table2
)
SELECT a.*
FROM mostrecent a
LEFT OUTER JOIN table1 b ON a.pattern = b.pattern AND b.user_id = {current_user}
WHERE b.id IS NULL AND a.rank = 1