基于 SQL (BigQuery) 中的多列返回许多小数据样本
Posted
技术标签:
【中文标题】基于 SQL (BigQuery) 中的多列返回许多小数据样本【英文标题】:Return many small data samples based on more than one column in SQL (BigQuery) 【发布时间】:2018-03-22 17:41:51 【问题描述】:在这个例子中,我有一个图书数据库,每本书有一条记录。记录包含书的所有者、类型和其他一些信息。我需要返回每个所有者、每个流派的前 20 名样本。
我计划这样做的方式是以编程方式构建一个巨大的查询,例如:
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE "%HORROR%" AND Owner LIKE "Alex" LIMIT 20)
UNION ALL
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE
"%COMEDY%" AND Owner LIKE "Alex" LIMIT 20)
UNION ALL
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE
"%HORROR%" AND Name LIKE "Sarah" LIMIT 20)
UNION ALL
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE
"%COMEDY%" AND Owner LIKE "Sarah" LIMIT 20)
UNION ALL
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE
"%HORROR%" AND Owner LIKE "James" LIMIT 20)
UNION ALL
(SELECT Owner, Genre, Data_one, Data_two FROM `dataset-table` WHERE Genre LIKE "%COMEDY%" AND Owner LIKE "James" LIMIT 20)
但是,我需要同时为几百个用户和 6 个流派执行此操作,我在 BigQuery 中收到一个错误,提示查询太复杂。
有没有人知道如何根据多个类别退回大量有限样本?如果它们最终出现在一个大数据集中,那很好。
例如:
Owner | Genre | Data_one | Data_two
Alex | Horror | Stephen King | IT
.... 100 more Horror books from Alex ....
Sarah | Horror | Darren Shan | Lord Loss
.... 100 more Horror books from Sarah ....
Alex | Comedy | Russel Brand | MBW
.... 100 more Comedy books from Alex ....
我会退回 Alex 的 20 部恐怖书、Sarah 的 20 部恐怖书和 Alex 的 20 部喜剧中的任何样本。
【问题讨论】:
请向我们提供所有者、名称、流派、data_one 和 data_two 的示例数据以及您的预期结果。 完成了,我实际上在原版中混淆了 Name 和 Owner,它们是同一个字段。 查看答案 - 它就是这样做的! 【参考方案1】:以下是 BigQuery 标准 SQL 的示例
它使用bigquery-public-data.medicare.physicians_and_other_supplier_2012
公共数据和姓名、城市、组织用于模仿您的作者、流派、数据
#standardSQL
WITH `project.dataset.table` AS (
SELECT
nppes_provider_first_name name,
nppes_provider_city city,
nppes_provider_last_org_name org
FROM `bigquery-public-data.medicare.physicians_and_other_supplier_2012`
), search AS (
SELECT name, city FROM
UNNEST(['JOHN','MICHAEL','DAVID','ROBERT']) name,
UNNEST(['NEW YORK','SPRINGFIELD','COLUMBUS','HOUSTON','DALLAS']) city
)
SELECT name, city, org FROM (
SELECT name, city, ARRAY_AGG(DISTINCT org LIMIT 20) orgs
FROM `project.dataset.table`
JOIN search USING(name, city)
WHERE RAND() < 0.5
GROUP BY name, city
), UNNEST(orgs) org
ORDER BY name, city, org
所以对于您的情况 - 它可能如下所示
#standardSQL
WITH search AS (
SELECT name, genre FROM
UNNEST(['Alex','Sarah','James','Robert']) name,
UNNEST(['HORROR','COMEDY') genre
)
SELECT name, genre, org FROM (
SELECT t.name, t.genre, ARRAY_AGG(DISTINCT t.org LIMIT 20) orgs
FROM `project.dataset.table` t JOIN search s
ON LOWER(s.name) = LOWER(t.name)
AND LOWER(s.genre) = LOWER(t.genre)
WHERE RAND() < 0.5
GROUP BY t.name, t.genre
), UNNEST(orgs) org
ORDER BY name, genre, org
当然,JOINing 的逻辑仍然在你身上——相等或 LIKE 或 REGEXP 等
【讨论】:
非常感谢您的回答,我让它几乎可以完美地处理我的数据集。当你说加入的逻辑在我身上时,你的意思是每个“组织”运行一次并将数据连接在一起吗?我目前正试图在将“Data_two org2”添加到顶部选择后同时显示“Data_one”和“Data_two”,但被“UNNEST(orgs)org”挫败。为什么“orgs”是复数形式? 编辑:我明白为什么它是复数的,长度为 20 的数组是 orgs,但我尝试在设置中添加第二个变量并将其更改为:UNNEST(orgs) org, UNNEST(orgs2) org2 和我从 60 个结果跃升至 1200 个!我真的很感谢你在这里的知识。会继续努力解决的。 通过加入逻辑,我的意思是 ON 子句 (LOWER(s.name) = LOWER(t.name) AND LOWER(s.genre) = LOWER(t.genre)
) 中的内容,正如我所提到的,这实际上取决于您要如何识别合格的流派和名称 - 通过平等、相似等。
如果您仍然对 data_one、data_two 有挑战 - 请发布新的具体问题,我们将很乐意回答。同时,请记住,这实际上取决于您实际表的架构。如果,例如,那些 data_one 和 dta_two 是组织记录的一部分 - 你可以在你的选择语句中使用org.data_one, org.data_two
(当然使用实际的字段名称):o)
谢谢,我实际上对架构和 JOIN 很好。我在这里创建了一个新问题,希望能解释我的新问题:***.com/questions/49454231/…【参考方案2】:
我认为你可以使用row_number()
:
select t.*
from (select t.*,
row_number() over (partition by name
order by (case when Genre like '%HORROR%' then 'HORROR'
when Genre like '%COMEDY%' then 'COMEDY'
end)
) as seqnum
from `dataset-table`
where name in ('Alex', 'Sarah', 'James') and
(genre like '%HORROR%' or genre like '%COMEDY%')
) t
where seqnum <= 20;
这不是 100% 等效的,因为任何归类为“恐怖喜剧”的电影也将被视为“恐怖”。另一方面,genre
不应包含多个值,除非它是重复记录或 JSON。在一个字符串中存储多个值是一种 SQL 反模式。
【讨论】:
以上是关于基于 SQL (BigQuery) 中的多列返回许多小数据样本的主要内容,如果未能解决你的问题,请参考以下文章