我有一张桌子:
c1|c2|c3|c4
-----+--+--+----
a b c 10
a a b 20
c a c 10
b b c 10
c b c 30
我想编写一个输入为3个字符串/文本的函数,例如(' abc , bd , c '),比较每个元素相互之间,找出这个组合是否存在一行,并将第四个( c4 )列的数量加起来。但如果存在 b a c 或 c a b 的星座,它将匹配 a b c 10 。如果有像 b c c 这样的行,那么它就不会像 c b b 那样。每场比赛都是独一无二的。
我认为最好的方法是使用string_to_array(文本,文本)。
我把一些伪代码放在一起,但不知道如何在SQL中编写它。也许逻辑也是错误的。
function (x,y,z)
res = 0
x_array = string_to_array(x, ' ')
y_array = string_to_array(y, ' ')
z_array = string_to_array(z, ' ')
foreach(x_item in x_array)
foreach(y_item in y_array)
foreach(z_item in z_array)
if (c1 = (x_item || y_item || z_item ) && c2 = (x_item || y_item || z_item ) && c3 = (x_item || y_item || z_item ))
res++
编辑
答案 0 :(得分:2)
我认为这可能是你想要的:
从给定的三个标记集与列c4
匹配的所有行中返回列(c1, c2, c3)
的总和。
<击> 撞击>
<击>使用contains @>
and is contained <@
by operators更加简单:
SELECT sum(c4) AS sum_of_matching_c4
FROM tbl
WHERE ARRAY[c1,c2,c3] <@ ARRAY['b', 'a', 'c'] -- strings in arbitrary order
AND ARRAY[c1,c2,c3] @> ARRAY['b', 'a', 'c'];
击> <击> 撞击>
很抱歉,对于('b', 'c', 'c')
与('c', 'b', 'b')
相比,这会失败。
WITH i(arr) AS (
SELECT ARRAY(VALUES ('b'), ('c'), ('c') ORDER BY 1) -- input once
) -- in arbitrary order
SELECT sum(c4) AS sum_of_matching_c4
FROM (
SELECT c4, array_agg(x ORDER BY x) AS arr
FROM (
SELECT ctid, c4, unnest(ARRAY[c1,c2,c3]) AS x
FROM tbl t, i
WHERE ARRAY[c1,c2,c3] <@ arr -- optional pre-selection
AND ARRAY[c1,c2,c3] @> arr -- for better performance?
) a
GROUP BY ctid, c4
) b
JOIN i USING (arr)
主要困难是在行中订购列的值。
对于你的输入(3个字符串),我在WHERE
子句中使用CTE中的VALUE
表达式实现了这一点,我立即订购并将其收集到一个数组中。为方便起见,我使用CTE,因此我们只需在一个地方输入值。
行值更复杂。我将三列放在一个数组中,并将其分解为unnest()
行。由于您没有提供主键,我使用ctid
作为ad-hoc代理主键 - 我需要GROUP BY
将现在排序的(c1, c2, c3)
填充到数组中。
最后,我总结了现在排序的数组完全匹配的所有c4
行。
注意:我明确表示不使用string_agg()
,因为不会产生不同的结果。考虑:
'abc' 'cde' 'fgh'
'ab' 'ccdef' 'gh'
..如果连接,则产生相同的字符串。
您可以考虑保存预订数据以加快查询速度。在飞行中这样做很昂贵。即您可以预先生成已排序的数组并将其保存为冗余列,然后您可以使用索引支持。冗余数据存储的成本应该快几个数量级 如果您正在处理长字符串,那么类似于我在此related answer on dba.SE中概述的解决方案可能是最好的做法。
或者(首选!)保证(c1, c2, c3)
始终按升序存储。您可以使用触发器BEFORE INSERT OR UPDATE
来保持订购行内的值。没有冗余存储,您只需在三列上创建multi-column index并逐一进行比较(而不是像我的示例中那样比较数组)。
答案 1 :(得分:0)
您无需为此编写函数。
首先,postgresql(sql)没有“字符串”,它是“text”或“varchar”。
其次,您需要的是这样的SQL查询:
SELECT ( DISTINCT ( c1 || c2 || c3 )) AS txtcol, SUM (c4) AS rowsum;
或
SELECT ( DISTINCT ( c1 || c2 || c3 )) AS txtcol, SUM(c4) AS numsum GROUP BY txtcol;
目前无法回想起确切的语法,你需要解决它, 无论如何,重点是你需要将varchar列与一些内置的连接起来 像CONCAT或“||”这样的功能运算符,然后按数字列汇总/分组。一切你需要的 是连接列,并为结果列提供一个名称。 确切地说,您甚至不需要在结果表上显示连接列, 例如,你可以只输出sums和sumarized的行数。
理论上你可以为此编写SQL函数或PL / SQL函数,但我确定它没有必要,你的情况似乎很简单,能够在没有函数的情况下实现你想要的结果。内置的sumarizing函数SUM()被称为“聚合”函数,聚合函数的其他示例例如是MIN()或MAX()。 请注意您实际尝试执行的操作,即通过每行连接的效果对某些结果VARCHAR列进行分组。
编辑:SQL中的“数组”或程序SQL是一些内部处理的数组,不要将它们与关系混淆(数据库中的表,也不将表作为SELECT结果)。我认为你也不需要SQL数组,这个任务真的不像看起来那么难。