我有几行记录(id, query,count
),我想通过观察多行上的query
来折叠。我想保留最长query
的行和count
字段的总和。
样本输入:
24, que, 2
24, querie, 1
24, queries, 1
25, term1, 3
25, term1+term2, 11
25, term1+term2+term3, 1
26, inventory, 5
26, issues, 10
27, close, 1
27, sclosed, 2
28, abcde, 2
28, abcfe, 2
必填输出:
24, queries, 4
25, term1+term2+term3, 15
26, inventory, 5
26, issues, 10
27, close, 1
27, sclosed, 2
28, abcde, 2
28, abcfe, 2
我只是在特殊情况下使用子字符串:24,25
被折叠,而27
没有被折叠,这是由于close
上的前缀。 26
也不会折叠,因为第二行中的query
字段不是第一行的子字符串(没有前缀)。
编辑:添加了ID 28
,这是另一种不应折叠记录的情况。
答案 0 :(得分:4)
对于更一般的情况(例如“差异可能在第10个字母处” 或“一行仅包含一个字符” ),您需要确定正确的群体。因此,有必要对照下一行检查行:“当前行是下一行的开始吗?”
使用substring
之类的东西,您可以在开头检查特殊长度(“将所有以相同的3个字母开头的文本分组” 但是如果您没有3个字母怎么办?还是区别在于以后?)
这就是为什么我借助lag
窗口函数(https://www.postgresql.org/docs/current/static/tutorial-window.html)计算特殊组的原因:
SELECT
max(id) as id, -- C
max(phrase) as phrase,
sum("count") as count
FROM (
SELECT
*,
SUM(is_diff) OVER (ORDER BY id, phrase) as ranked -- B
FROM (
SELECT
*,
-- A:
CASE WHEN phrase LIKE (lag(phrase) over (order by id, phrase)) || '%' THEN 0 ELSE 1 END as is_diff
FROM phrases
)s
) s
GROUP BY ranked
ORDER BY ranked
讨论了主要思想here。
A:lag
函数允许检查下一行的值。因此,如果当前行的phrase
是下一行phrase
的开始,则它们在同一组中。 (current_row LIKE (next_row || '%')
)。之所以有效,是因为id
组按phrase
个文本(及其长度)排序。
如果行不兼容,则将辅助变量设置为1
,否则设置为0
。
B:可以添加帮助程序变量并生成组。 (有关更多详细信息,请参见上面提供的链接。)
C:剩下的就是根据新生成的组值进行简单分组了。
答案 1 :(得分:0)
将聚合用于最大值和总和,并按列分组应为id和substring(column2,从1到3),因为您遵循某种总价值模式
select id, max(column2), sum(column3)
from tablename
group by id, substring(column2,from 1 for 3)
答案 2 :(得分:0)
如果您需要agreagtio作为id,则可以使用sum来获取总数,并使用max来获取名称
select id, max(col2), sum(col3)
from my_table
group by id
如果您需要按ID进行汇总的期望 并获得27个折叠的您可以使用
select id, max(col2), sum(col3)
from my_table
where id <>27
group by id
union all
select id, col2, sum(col3)
from my_table
where id =27
group by id, cold2
order by id
答案 3 :(得分:0)
使用聚合无法解决此任务-因为在您的情况下,因为分组子集由相等定义,并且您要使用子字符串操作。
因此您需要实现自己的集合返回函数:
create table foo(id int, query text, count int);
CREATE OR REPLACE FUNCTION public.reduce()
RETURNS SETOF foo
LANGUAGE plpgsql
AS $function$
declare r foo; sr foo;
begin
for r in select * from foo order by id, query
loop
if sr.id is null then
sr := r;
else
if sr.id = r.id then
if r.query like sr.query || '%'
or sr.query like r.query || '%'
then
if length(r.query) > length(sr.query) then
sr.query := trim(r.query);
end if;
sr.count := sr.count + r.count;
else
return next sr;
sr := r;
end if;
else
return next sr;
sr = r;
end if;
end if;
end loop;
if sr.id is not null then
return next sr;
end if;
end;
$function$
postgres=# select * from reduce();
+----+-------------------+-------+
| id | query | count |
+----+-------------------+-------+
| 24 | queries | 4 |
| 25 | term1+term2+term3 | 15 |
| 26 | inventory | 5 |
| 26 | issues | 10 |
| 27 | close | 1 |
| 27 | sclosed | 2 |
+----+-------------------+-------+
(6 rows)
字符串操作可能很慢,但是此任务是无关紧要的,仅使用SQL是不可能的。
答案 4 :(得分:-1)
select id, max(col2), sum(col3)
from tablename
where id in (24,25)
group by id
union all
select id, col2, sum(col3)
from tablename
where id not in (24,25)
group by id,col3
order by id,3;