SQL: 如何将多个查询连接在一起?

SQL: how to join multiple queries together?

我有一个 table 的购买决定,如下所示:

org_id    item_id    spend
--------------------------
123        AAB         2
123        AAC         4
124        AAB        10
124        AAD         5

我想找到所有只被三个或更少组织购买的项目,然后我想按总支出以及组织的 ID 对它们进行排序。

这是我获取该列表中项目的查询:

SELECT
  item_id,
  EXACT_COUNT_DISTINCT(org) AS org_count,
  SUM(spend) AS total_spend
FROM
  [mytable]
GROUP BY
   item_id
HAVING
  org_count < 4
ORDER BY
  total_spend DESC

它给我的结果如下所示:

item_id    total_spend
--------------------------
AAB         12
AAC         4
AAD         5

但我需要将此查询扩展到 return 这些组织的 ID。

这可以在单个查询中实现吗,还是我需要在多个查询中实现?

自行获取组织 ID 的查询如下所示:

SELECT 
  org 
FROM 
  mytable
WHERE item_id IN (SELECT item_id ... etc, query as above)

但我不确定如何将两者粘合在一起。

更新:理想情况下,我最终会得到一些与原始 table 非常相似的东西,但只包含由三个或更少的组织购买的那些物品:

org_id    item_id    spend
--------------------------
123        AAB         2
123        AAC         4
124        AAB        10
124        AAD         5

尝试这样查询。在结果集中,您将看到由该组织或更少组织购买的所有项目和总支出

SELECT T2.org_id,
       T.item_id
FROM table AS T2
JOIN
    (SELECT item_id,
           SUM(spend) AS total_spend 
    FROM table AS T
    GROUP BY T.item_id
    HAVING COUNT(DISTINCT org_id) < 4) AS T ON T.item_id = T2.item_id
ORDER BY T.total_spend DESC

您想要的函数是sort-ofGROUP_CONCAT()。但是,bigquery 中没有 DISTINCT 选项。所以,使用子查询:

SELECT item_id, COUNT(*) AS org_count,
       SUM(io_spend) AS total_spend,
       GROUP_CONCAT(org, ', ') as orgs
FROM (SELECT item_id, org, SUM(spend) as io_spend
      FROM t
      GROUP BY item_id, org
     ) io
GROUP BY item_id
HAVING org_count < 4
ORDER BY total_spend DESC;

编辑:

如果您对单独行中的 ID 感到满意,那么以下是可能适用于 Bigquery 的 SQL 版本:

SELECT item_id, org,
       SUM(spend) as org_spend,
       SUM(SUM(spend)) OVER (PARTITION BY item_id) as total_spend,
       COUNT(*) OVER (PARTITION BY item_id) as numOrgs
FROM t
GROUP BY item_id, org
HAVING numOrgs < 4;

在 BigQuery 中 - JOINs 有时非常令人头疼(取决于多种因素),因此在您的武器库中拥有一些 non-join 解决方案总是好的。

下面是一些基于 Window functions 的示例:
我认为无论是从实用还是学习的角度来看,它们都很有趣

选项 #1 - 使用 group_concat/regexp 技巧

SELECT org_id, item_id, spend
FROM (
  SELECT org_id, item_id, spend,
    GROUP_CONCAT(STRING(org_id)) OVER(PARTITION BY item_id) AS orgs
  FROM table
)
WHERE 1 + LENGTH(REGEXP_REPLACE(orgs, r'[^,]', '')) < 4
ORDER BY item_id, org_id

选项 #2 - 假设每个项目的平均组织数量不是太大(因此不同的计数更不准确):

SELECT org_id, item_id, spend
FROM (
  SELECT org_id, item_id, spend,
    COUNT(DISTINCT org_id) OVER(PARTITION BY item_id) AS orgs
  FROM table
)
WHERE orgs < 4
ORDER BY item_id, org_id