【问题标题】:Group by query in postgresql在 postgresql 中按查询分组
【发布时间】:2014-03-27 11:51:07
【问题描述】:

我有两张桌子

表 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. 模式必须不同

我已经尝试使用 php 代码执行 3 次查询,并且需要很长时间

  1. 从 table2 中按模式选择 distinct(pattern)
  2. select * from table1 where user_id = login_id
  3. php 中的 foreach 循环(从 table2 中选择 *,其中 id 不在(query2 的输出)和类似 ('123') 的模式)

那么是否可以在 postgresql 中使用单个查询

【问题讨论】:

  • 我几乎什么都不懂。请更详细地描述您的问题。您想要表 2 的所有行,其模式在表 1 的 user_id = 当前用户的部分中不存在?
  • @GhostGambler 是的
  • 那么:为什么需要的输出中只有一个^13.* 模式?
  • @joop nope 需要的模式是 20,13,14,在表 1 中未出现 user_id =13

标签: postgresql


【解决方案1】:

这应该可以解决问题:

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 中的所有行连接起来,根据它们的模式并且仅当它属于当前用户时。然后只从a中选择那些无法加入的。

更新

根据您的评论,我再次不能 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 并(如前所述)仅选择那些在表 1 中没有行的行。

另一种特别适用于 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

【讨论】:

  • 感谢它真的很好用。但是如果表 2 中有超过 1 条相同模式的记录可用,那么它会显示相同模式的所有记录,但我只想要表 2 的不同模式
  • 我已经更改了第一个解决方案并添加了另一个解决方案,它返回的结果略有不同,在我的原始答案中。
  • 非常感谢您的回复,但正如您所说,它现在只显示不同的模式,但我想要不同的模式以及该模式的完整细节,所以这可能吗?
  • 如果没有进一步的说明,这是不可能的。如果您只想要表 2 中的不同模式,那没关系,但如果您还想要其他列,则必须说明附加数据应该来自哪一行。目前唯一的附加数据是start_date,所以应该总是返回最新的start_date
  • 不,我还有一些附加字段,但所有这些都仅在 table2 中可用,例如评论(文本),没有提及,但我还想选择评论以及 start_date,仅此而已
猜你喜欢
  • 2023-01-20
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 2015-06-12
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
相关资源
最近更新 更多