这是一个问题,我不知道如何搜索甚至描述。但我会尝试一下。
首先,我有两张桌子:
CREATE TABLE vch
(vchid int4, subject text);
INSERT INTO vch
(vchid, subject)
VALUES
(1, 'Volvo'),
(2, 'Ford'),
(3, 'Jeep'),
(4, 'Toyota');
CREATE TABLE rec
(recid int4, recvch int4, recname text);
INSERT INTO rec
(recid, recvch, recname)
VALUES
(1000, 1,'xxx'),
(2000, 1,'yyy'),
(3000, 3,'zzz'),
(4000, 4,'aaa');
我的目标是创建一个如下所示的输出:
1 Volvo
{
1000 xxx
2000 yyy
}
3 Jeep
{
3000 zzz
}
4 Toyota
{
4000 aaa
}
它看起来与json有关,但格式如上。
我最接近的是:
SELECT vchid, 0 as id, subject FROM vch
UNION ALL
SELECT recvch, recid, recname FROM rec
ORDER BY 1
sqlfiddle:http://sqlfiddle.com/#!15/d3a61d/12
答案 0 :(得分:2)
如果您可以在输出中嵌入换行符,则可以使用以下命令:
with all_rows (id, recid, name, label, src) as (
SELECT vchid, null as id, subject, concat(vchid, ' ', subject), 1
FROM vch
where exists (select 1 from rec where rec.recvch = vch.vchid)
UNION ALL
SELECT recvch, recid, recname, concat(recid, ' ', recname), 2
FROM rec
)
select case
when recid is not null and count(*) over (partition by id) <= 2 then concat('{', chr(10), label, chr(10), '}')
when recid is not null and row_number() over (partition by id order by recid) = 1 then concat('{', chr(10), label)
when recid is not null
and row_number() over (partition by id order by src, recid) = count(*) over (partition by id) then concat(label, chr(10), '}')
else label
end as label
from all_rows
order by id, src, recid nulls first;
输出:
1 Volvo
{
1000 xxx
2000 yyy
}
3 Jeep
{
3000 zzz
}
4 Toyota
{
4000 aaa
}
但是,例如
{
4000 aaa
}
是单行(和列),但包含嵌入的换行符。
这取决于您如何导出该数据(如果适用于您)(psql将显示+
以指示输出中的换行)
当然,您需要使用适合您平台的换行符替换chr(10)
(换行符)(例如,适用于Windows的chr(13), chr(10)
)
另一个选择是创建一个执行此操作的函数。可能更容易处理:
create or replace function get_result()
returns setof text
as
$$
declare
v_rec record;
r_rec record;
begin
for v_rec in SELECT vchid, subject
FROM vch
where exists (select 1 from rec where rec.recvch = vch.vchid)
order by vchid
loop
return next concat(v_rec.vchid, ' ', v_rec.subject);
return next '{';
for r_rec in select recid, recname
from rec
where recvch = v_rec.vchid
order by recid
loop
return next concat(r_rec.recid, ' ', r_rec.recname);
end loop;
return next '}';
end loop;
end;
$$
language plpgsql;
然后只需运行:
select *
from get_result();
答案 1 :(得分:2)
这给出了一行结果,文本输出除以换行符:
select
string_agg(
format(
e'%s %s\n{\n%s\n}',
vchid, subject, rec
),
e'\n' order by 1
) as result
from (
select
vchid,
subject,
string_agg(
format(
e'%s %s ',
recid, recname
),
e'\n'
) as rec
from vch
join rec on vchid = recvch
group by 1, 2
) s;
结果:
result
-----------
1 Volvo +
{ +
1000 xxx +
2000 yyy +
} +
3 Jeep +
{ +
3000 zzz +
} +
4 Toyota +
{ +
4000 aaa +
}
(1 row)
您可以将unnest(string_to_array())
添加到上述查询中,以便将每一行放在一行中:
select
unnest(string_to_array(result, e'\n')) as result
from (
select
string_agg(
format(
e'%s %s\n{\n%s\n}',
vchid, subject, rec
),
e'\n' order by 1
) as result
from (
select
vchid,
subject,
string_agg(
format(
e'%s %s ',
recid, recname
),
e'\n'
) as rec
from vch
join rec on vchid = recvch
group by 1, 2
) s
) s;
结果:
result
-----------
1 Volvo
{
1000 xxx
2000 yyy
}
3 Jeep
{
3000 zzz
}
4 Toyota
{
4000 aaa
}
(13 rows)
答案 2 :(得分:1)
您的问题并不完全清楚您期望的结果。 但是,我想这里有一个可能的解决方案,可以产生类似于你想要的东西。
您可以使用array_agg()
函数和string concatenation来生成字符串数组
SELECT vchid, subject, array_agg(rec.recid || ' ' || rec.recname) AS rec
FROM vch JOIN rec ON vch.vchid = rec.recvch
GROUP BY vch.vchid, vch.subject;
结果
vchid | subject | rec
------+---------+------------------------
1 | Volvo | {"1000 xxx","2000 yyy"}
3 | Jeep | {"3000 zzz"}
4 | Toyota | {"4000 aaa"}
答案 3 :(得分:1)
另一种可能的解决方案:
1-构建一个由所有记录的昏迷分隔的字符串 2-从字符串中创建一个数组 3-最后使用unexst展开数组。
select unnest(string_to_array(
(vchid::text || ' ' || subject
|| ',{'::text
|| ','
|| (select string_agg(format(e'%s %s', rec.recid, rec.recname), ',')
from rec where vch.vchid = rec.recvch)::text
|| ',}'::text)::text
, ','))
from vch;
最终结果:
+----------+
| result |
+----------+
| 1 Volvo |
+----------+
| { |
+----------+
| 1000 xxx |
+----------+
| 2000 yyy |
+----------+
| } |
+----------+
| 3 Jeep |
+----------+
| { |
+----------+
| 3000 zzz |
+----------+
| } |
+----------+
| 4 Toyota |
+----------+
| { |
+----------+
| 4000 aaa |
+----------+
| } |
+----------+
这是一组行,如果您要查找一个文本列,@ a_horse_with_no_name已提供正确的答案。
实际上,您可以通过向每行添加LF来使用提供的查询来获取一条记录。
select string_agg(f, chr(10))
from (select unnest(string_to_array(
(vchid::text || ' ' || subject
|| ',{'::text
|| ','
|| (select string_agg(format(e'%s %s', rec.recid, rec.recname), ',')
from rec where vch.vchid = rec.recvch)::text
|| ',}'::text)::text
, ',')) f
from vch) a
;
就是这样:
+----------+
| result |
+----------+
| 1 Volvo |
| { |
| 1000 xxx |
| 2000 yyy |
| } |
| 3 Jeep |
| { |
| 3000 zzz |
| } |
| 4 Toyota |
| { |
| 4000 aaa |
| } |
+----------+