Clickhouse LEFT JOIN 部分匹配(或子选择)
Posted
技术标签:
【中文标题】Clickhouse LEFT JOIN 部分匹配(或子选择)【英文标题】:Clickhouse LEFT JOIN with partial match (or subselect) 【发布时间】:2020-08-25 14:57:18 【问题描述】:实际上 CH 不支持带有部分匹配(字符串等)的左连接,所以我试图在表达式列表中使用 select 子句构建查询,但它不起作用。 或者也许有一种全新的方式(对我来说)可以做到这一点,但我只是在寻找关于如何执行此操作的线索。
错误是“缺少列:'DomainName' while processing query”
select NumberInTypes,
DomainName,
Url,
(select aa.group_name
from (select t1.id, t1.url_part, ugu.name as group_name
from Url t1
any
left join (select id, urlgroup_id, url_id, ug.name
from UrlGroupUrl t2
any
left join (select id, name
from UrlGroup t3
) ug on t2.urlgroup_id = ug.id
) ugu on t1.id = ugu.url_id) aa where t1.Url like '%' || aa.url_part || '%'
) as UrlGroup,
KeywordId,
ResultId,
HashedContent,
SearchEngine,
client_name,
project_name,
group_name,
DateParsed
from PositionNew t1
any
left join (
select id as KeywordId, trimBoth(keyword) as keyword, groupid, group_name, project_name, client_name
from Keyword
any
left join (
select keywordgroup_id as groupid, keyword_id as KeywordId, group_name, project_name, client_name
from KeywordGroupKeyword
any
left join (
select id as groupid, name as group_name, project_id, project_name, client_name
from KeywordGroup
any
left join (
select id as project_id, name as project_name, client_id, client_name
from Project
any
left join (
select id as client_id, name as client_name from Client
) client using client_id
) project using project_id
) kgroup using groupid
) keywordgroup using KeywordId
) keyword using KeywordId
where DateParsed between '2020-07-13' and '2020-08-02'
and PositionType in (1, 3)
and client_name like '%ClientName%'
ORDER BY ResultId,
DomainName,
NumberInType
LIMIT
1 BY ResultId, DomainName;
更新: 显然,您不能在 Clickhouse 的相关子查询中使用 out 查询中的列。所以我完全没有选择,开始认为这是不可能的。
重现问题的简化示例:
第一个表包含 URL
+------------------------------------+
| Url |
+------------------------------------+
| https://example.com/cat/page1.html |
+------------------------------------+
| https://example.com/cat/page2.html |
+------------------------------------+
| https://example2.com/page.html |
+------------------------------------+
第二个表包含 UrlGroups
+-----------------+-----------+
| UrlPart | GroupName |
+-----------------+-----------+
| example.com/cat | DomainCat |
+-----------------+-----------+
| example2.com | Domain2 |
+-----------------+-----------+
我想要实现的是:
+------------------------------------+-----------+
| Url | GroupName |
+------------------------------------+-----------+
| https://example.com/cat/page1.html | DomainCat |
+------------------------------------+-----------+
| https://example.com/cat/page2.html | DomainCat |
+------------------------------------+-----------+
| https://example2.com/page.html | Domain2 |
+------------------------------------+-----------+
ALL LEFT JOIN - 不起作用,因为它需要完全匹配 SUBQUERY - 不起作用,因为您不能使用外部查询中的列来过滤其结果
【问题讨论】:
很难重现你的问题——你能提供所有使用过的表的架构吗?或重现此问题的简单示例。 @vladimir 我已经用简化的例子更新了这个问题 【参考方案1】:让我们依靠数组操作:
WITH
(
SELECT (groupArray(UrlPart), groupArray(GroupName))
FROM
(
/* Emulate 'UrlGroups' table. */
SELECT
data.1 AS UrlPart,
data.2 AS GroupName
FROM
(
SELECT arrayJoin([
('example.com/cat', 'DomainCat'),
('example2.com', 'Domain2')]) AS data
)
)
) AS urls_groups
SELECT
Url,
arrayElement(
urls_groups.2,
multiSearchFirstIndexCaseInsensitiveUTF8(Url, urls_groups.1)) AS GroupName
FROM
(
/* Emulate 'Urls' table. */
SELECT data AS Url
FROM
(
SELECT arrayJoin([
'https://example.com/cat/page1.html',
'https://example.com/cat/page2.html',
'https://example2.com/page.html',
'https://example_unknown.com/page.html']) AS data
)
)
/*
┌─Url───────────────────────────────────┬─GroupName─┐
│ https://example.com/cat/page1.html │ DomainCat │
│ https://example.com/cat/page2.html │ DomainCat │
│ https://example2.com/page.html │ Domain2 │
│ https://example_unknown.com/page.html │ │
└───────────────────────────────────────┴───────────┘
*/
您应该定义使用哪个函数 - multiSearchFirstIndexCaseInsensitiveUTF8 或 multiSearchFirstIndexCaseInsensitive。
【讨论】:
使用简化示例,但是当我尝试使用真实数据时,我得到“DB::Exception: Scalar17022771055411946142_18430558166935724235
不存在(内部错误)(版本 20.4.5.36(官方构建)) )" 错误...
奇怪 - 我已经注释掉 WHERE CLAUSE,现在它可以工作了......@vladimir
最后,我不得不将整个查询(使用 WHERE CLAUSE,但没有那个 arrayElement 的东西)放在另一个 SELECT 中,然后我把 arrayElement 放在那里。这样就成功了。谢谢弗拉基米尔!
@EdgardGomezSennovskaya 很高兴为您提供帮助。以上是关于Clickhouse LEFT JOIN 部分匹配(或子选择)的主要内容,如果未能解决你的问题,请参考以下文章
sql中left join、right join、inner join有啥区别
关于mysql中的left join和left outer join的区别