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
我有一个 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