使用PostgreSQL 8.4,我已经成功地能够使用ARRAY_AGG()取多个订单的情况下,让每个客户单行:如何通过array_agg遍历迭代列?
从这:
order_id|customer_id|order_date |order_desc
1 |1 |"2010-01-01"|"Tom's First"
2 |1 |"2010-04-01"|"Tom's Second"
7 |1 |"2010-04-13"|"Tom's Third"
8 |1 |"2011-04-13"|"Tom's Last"
5 |1 |"2011-06-20"|"Tom's Really Last."
3 |2 |"2010-07-07"|"Dick's First"
6 |2 |"2011-07-07"|"Dick's Other"
4 |3 |"2011-04-04"|"Harry's Only"
使用此:
select cu.customer, array_agg(ord.order_id) as orders from test_order ord
inner join test_customer cu
on ord.customer_id = cu.customer_id
group by cu.customer
结果:
customer |orders
"Tom" |"{1,2,7,8,5}"
"Dick" |"{3,6}"
"Harry" |"{4}"
的d我可以抓住阵列片创建新列,如果我硬代码每个迭代:
select cu.customer,
(array_agg(ord.order_id))[1] as order_1,
(array_agg(ord.order_id))[2] as order_2,
(array_agg(ord.order_id))[3] as order_3,
(array_agg(ord.order_id))[4] as order_4,
(array_agg(ord.order_id))[5] as order_5
from test_order ord
inner join test_customer cu
on ord.customer_id = cu.customer_id
group by cu.customer
结果:
customer|order_1|order_2|order_3|order_4|order_5
"Dick" |3 |6 | | |
"Harry" |4 | | | |
"Tom" |8 |1 |5 |2 |7
然而,想什么,我做的,在两个步骤:
For循环我的方式通过记录,以便我不必创建该字段的每个迭代。好消息是上面的结构没有错误,只是传递NULL,但是如果我遇到了一些疯狂的记录,我不必在我的声明中手动创建order_55,order_56等。
更妙的是最终没有通过其特定的领域,有它在所有的领域进行迭代(除非该CUSTOMER_ID),给我的每场的迭代,该效果:
customer|order_id1|order_date1|order_desc1|order_id2|order_date2|order_desc2| ...
等等基本上加入父表(客户)的子(订单),但有多个子记录跨越一行而不是创建倍数。
(是的,我知道这与您为什么首先执行父/子表的基本概念相反,不过,我将此传递给客户端,这将使该过程变得更加容易。)
更新:我已经得到了与拆解功能更接近......我第一次称呼它,它创建的列和填充的客户之一。但由于某些原因,我的IF NOT EXISTS在单独运行时工作,但不在函数内:我得到“column order_id1 exists”错误。我也想最终修改这个,以便特定的字段不被硬编码;而不是customer_id我想要做一些事情,比如传递父表,子表和连接ID,并且用这种交叉表方式完全追加子表。
CREATE FUNCTION loop_test(integer) RETURNS integer AS $$
DECLARE
rOrder RECORD;
loop_counter INT := 1;
target_customer_id ALIAS FOR $1;
BEGIN
FOR rOrder IN SELECT *
FROM vdad_data.test_order
WHERE customer_id = target_customer_id
ORDER BY order_id LOOP
IF NOT EXISTS
(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME= 'order_id' || loop_counter
AND TABLE_NAME='test_customer'
AND TABLE_SCHEMA='vdad_data'
)
THEN
EXECUTE 'ALTER TABLE vdad_data.test_customer
ADD COLUMN order_id' || loop_counter || ' integer';
END IF;
IF NOT EXISTS
(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME= 'order_date' || loop_counter
AND TABLE_NAME='test_customer'
AND TABLE_SCHEMA='vdad_data'
)
THEN
EXECUTE 'ALTER TABLE vdad_data.test_customer
ADD COLUMN order_date' || loop_counter || ' date';
END IF;
IF NOT EXISTS
(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME= 'order_desc' || loop_counter
AND TABLE_NAME='test_customer'
AND TABLE_SCHEMA='vdad_data'
)
THEN
EXECUTE 'ALTER TABLE vdad_data.test_customer
ADD COLUMN order_desc' || loop_counter || ' character varying';
END IF;
EXECUTE 'UPDATE vdad_data.test_customer
SET order_id' || loop_counter || ' = ' || rOrder.order_id ||',
order_date' || loop_counter || ' = ' || quote_literal(to_char(rOrder.order_date,'yyyy-mm-dd')) ||',
order_desc' || loop_counter || ' = ' || quote_literal(rOrder.order_desc) ||'
WHERE customer_id = ' ||rOrder.customer_id;
loop_counter = loop_counter + 1;
END LOOP;
RETURN 1;
END;
$$ LANGUAGE plpgsql;
我为是所有在地图上道歉,因为我一直在尝试了一次,我不能完全得到解决这个几件事情。任何帮助表示赞赏,谢谢!
您是否想要做一些类似[this crosstab](http://www.postgresql.org/docs/current/static/tablefunc.html#AEN126191)的函数? –
人。有点。我猜这是一个9.0的功能,因为我没有在8.4。但似乎仍然需要每个领域的手动硬编码?并且每个数据字段的标题不是由第三列(该示例中的“cat”值)确定的,它只是现有列标题的迭代:order_id变为order_id1,order_id2等。 – MitchO
@MitchO:它也在8.4。您需要安装contrib。 –