使用PostgreSQL 8.4,我已经成功地使用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}"
如果我对每次迭代进行硬编码,我可以抓取数组的一部分来创建新列:
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
然而,我想做的是分两步:
循环浏览记录,这样我就不必创建字段的每次迭代。好消息是上面的结构没有错误,只是传递NULL,但如果我得到一些疯狂的记录数,我不必在我的声明中手动创建order_55,order_56等。
更好的是最终不会将其传递给特定字段并让它遍历所有字段(除了customer_id)并给我每个字段的迭代,以达到以下效果:
customer|order_id1|order_date1|order_desc1|order_id2|order_date2|order_desc2| ...
等等。基本上将父表(客户)连接到子(订单),但是有多个子记录跨越单行而不是创建倍数。
(是的,我理解这与你为什么首先做父/子表的基本概念背道而驰。但是,我将它传递给客户端,这将使这个过程变得更加容易。)
更新:我已经接近了相似的功能......第一次调用它时,它会创建列并填充其中一个客户。但由于某种原因,我的IF NOT EXISTS在单独运行时起作用,但不在函数内:我得到“列order_id1存在”错误。我也想最终修改它,因此特定字段不是硬编码的;而不是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;
我为在地图上的所有人道歉,因为我一直试图解决有关此问题的一些事情,我无法理解。感谢任何帮助,谢谢!
答案 0 :(得分:1)
您是否尝试获取每个客户订单的序号?您可以使用Postgres 8.4中的row_number()函数执行此操作。在SQL中,为每个订单号创建单独的列是不可持续或高效的。
类似的东西:
select cu.customer,
row_number() OVER(PARTITION BY cu.customer ORDER BY ord.order_date)
from test_order ord inner join test_customer cu
on ord.customer_id = cu.customer_id
group by cu.customer
答案 1 :(得分:0)
此:
select array_agg(row(order_id,order_date,order_desc))
from (
select 1 order_id,1 customer_id,'2010-01-01' order_date,'Tom''s First' order_desc union
select 2 order_id,1 customer_id,'2010-04-01' order_date,'Tom''s Second' order_desc union
select 7 order_id,1 customer_id,'2010-04-13' order_date,'Tom''s Third' order_desc union
select 8 order_id,1 customer_id,'2011-04-13' order_date,'Tom''s Last' order_desc union
select 5 order_id,1 customer_id,'2011-06-20' order_date,'Tom''s Really Last.' order_desc union
select 3 order_id,2 customer_id,'2010-07-07' order_date,'Dick''s First' order_desc union
select 6 order_id,2 customer_id,'2011-07-07' order_date,'Dick''s Other' order_desc union
select 4 order_id,3 customer_id,'2011-04-04' order_date,'Harry''s Only' order_desc
) orders
group by orders.customer_id
给你三行:
"{"(2,2010-04-01,\"Tom's Second\")","(1,2010-01-01,\"Tom's First\")","(7,2010-04-13,\"Tom's Third\")","(5,2011-06-20,\"Tom's Really Last.\")","(8,2011-04-13,\"Tom's Last\")"}"
"{"(3,2010-07-07,\"Dick's First\")","(6,2011-07-07,\"Dick's Other\")"}"
"{"(4,2011-04-04,\"Harry's Only\")"}"
这看起来非常接近你所说的#34;甚至更好":
客户| order_id1 | order_date1 | order_desc1 | order_id2 | order_date2 | order_desc2 | ...
唯一的区别是:所有内容都包含在一个列中。当然,单个列是一个数组,每个元素都是一个复合类型,如果你展平那个结构,你就得到了你所要求的。如果当然这取决于你是否有办法进行压扁。