【问题标题】:Combinational SQL count query in PostgresPostgres 中的组合 SQL 计数查询
【发布时间】:2021-06-11 09:58:13
【问题描述】:

我有一些电台存储在一个简单的stations 集合中:

+----+-----------+
| id | name      |
+----+-----------+
| 1  | Station A |
+----+-----------+
| 2  | Station B |
+----+-----------+
| 3  | Station C |
+----+-----------+
| 4  | Station D |
+----+-----------+

我在rides 集合中存储了一些游乐设施:

+----+---------------+-------------+
| id | fromStationId | toStationId |
+----+---------------+-------------+
| 1  | 3             | 4           |
+----+---------------+-------------+
| 2  | 2             | 1           |
+----+---------------+-------------+
| 3  | 1             | 1           |
+----+---------------+-------------+
| 4  | 3             | 2           |
+----+---------------+-------------+

我想创建一个包含所有可能的fromStation 名称和toStation 名称对之间的所有站间游乐设施的计数列表,结果如下所示:

[
  {
    "fromStation": "Station A",
    "toStation": "Station A",
    "count": 1196
  },
  {
    "fromStation": "Station A",
    "toStation": "Station B",
    "count": 1
  },
  {
    "fromStation": "Station A",
    "toStation": "Station C",
    "count": 173
  },
]

And so on for all other combinations...

如何获得所有可能的两对车站名称组合,然后计算其中的骑行次数?我正在使用最新版本的 Postgres。

【问题讨论】:

  • 我假设您有一个简单的站点列表(一个包含一列的表)和一个组合站点的第二个表连接...如果您的布局不同,请向我们展示一些示例数据...
  • @S-Man 很好的答案!但是,我没有连接表。我只有一个简单的电台列表(一列),没有别的。我还修改了我的问题以增加清晰度:)

标签: sql postgresql aggregation


【解决方案1】:

先聚合游乐设施,然后将 ID 解析为名称:

SELECT f.name AS from_station, t.name AS to_station, count
FROM  (
   SELECT from_station_id, to_station_id, count(*) AS count
   FROM   rides
   GROUP  BY 1, 2
   ) r
JOIN   stations f ON f.id = r.from_station_id
JOIN   stations t ON t.id = r.to_station_id
ORDER  BY 1, 2;  -- optional order

当然,这只会产生与实际游乐设施的组合。如果您需要包含没有任何游乐设施的组合,则需要将OUTER 加入到stations 表的笛卡尔积中。比如:

-- include all combinations (even without rides)
SELECT from_station, to_station, COALESCE(count, 0) AS count
FROM  (
   SELECT from_station_id, to_station_id, count(*) AS count
   FROM   rides
   GROUP  BY 1, 2
   ) r
RIGHT  JOIN (
   SELECT f.id AS from_id, f.name AS from_station
        , t.id AS to_id  , t.name AS to_station
   FROM   stations f CROSS JOIN stations t
   ) s ON  s.from_id = r.from_station_id
      AND  s.to_id   = r.to_station_id
ORDER  BY 1, 2;  -- optional order

同样,在加入车站之前汇总游乐设施更便宜。

要将其包装为 JSON 数组或记录,只需:

SELECT json_agg(sub)
FROM  (
   -- query from above
   ) sub;

db小提琴here

【讨论】:

  • 非常感谢您的回答!为再次更改表的架构而道歉(我再次查看了我的数据库并意识到我的错误)。你能看看更新后的问题吗?
  • @DakshShah:我做了相应的调整。对于您的下一个问题,请记住从一开始就提供正确的信息。在给出答案后改变问题的性质显然不太理想。
  • 非常感谢,很抱歉给您带来麻烦!我会确保我这样做。
【解决方案2】:

demos:db<>fiddle

SELECT 
    c.from_station,
    c.to_station,
    COUNT(*)
FROM stations s1
JOIN stations s2 ON s1.station <> s2.station                                     -- 1
JOIN connections c ON s1.station = c.from_station AND s2.station = c.to_station  -- 2
GROUP BY c.from_station, c.to_station                                            -- 3
  1. 在工作站表上创建自联接。 &lt;&gt; 加入条件确保不会加入同一站。所有其他站点将相互连接,从而创建所有组合
  2. 使用自连接中的两个站列在连接表中加入此结果,用于连接的from 和to 点
  3. 现在您可以按from 和to 和COUNT(*) 进行分组聚合。

如果您想识别from station 等于to station 的情况,您可以更改

JOIN stations s2 ON s1.station <> s2.station

变成一个简单的:

CROSS JOIN stations s2

如果您想获取问题中所示的 JSON 对象:

SELECT 
    json_agg(connection)                      -- 2
FROM (
    SELECT 
        json_build_object(                    -- 1
            'fromStation', c.from_station,
            'toStation', c.to_station,
            'count', COUNT(*)
        ) as connection
    FROM stations s1
    JOIN stations s2 ON s1.station <> s2.station
    JOIN connections c ON s1.station = c.from_station AND s2.station = c.to_station
    GROUP BY c.from_station, c.to_station
) s
  1. 从您在上面创建的列中创建 JSON 对象
  2. 将它们聚合成一个 JSON 数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    相关资源
    最近更新 更多