将行转换为列 Firebird 2.1
Pivot rows into columns Firebird 2.1
我有一个table包含几公里约100
table of kilometers
我需要像这样将行旋转成列
pivot rows into columns
- 列数固定在行数=10
- 公里可以重复,有差距,例如:263, 263, 264, 265, 270..
我想用“with recursive”,但是网上的例子很少(
如果您能帮我解决问题,我将不胜感激!
正如我在评论中提到的,这可能是在您的表示层中更好地解决的问题,而不是通过查询。我不确定这是否可以通过(递归)CTE 解决,但我可以使用 EXECUTE BLOCK
在 PSQL 中为您提供解决方案(这也可以以存储过程的形式完成)。
此解决方案将行映射到列,并在所有列都已填充后开始新的一行。
execute block
returns (km_1 smallint, km_2 smallint, km_3 smallint, km_4 smallint, km_5 smallint,
km_6 smallint, km_7 smallint, km_8 smallint, km_9 smallint, km_10 smallint)
as
declare column_count smallint = 1;
declare km smallint;
begin
for select km from kms order by km into km do
begin
-- map value to column
if (column_count = 1) then km_1 = km;
else if (column_count = 2) then km_2 = km;
else if (column_count = 3) then km_3 = km;
else if (column_count = 4) then km_4 = km;
else if (column_count = 5) then km_5 = km;
else if (column_count = 6) then km_6 = km;
else if (column_count = 7) then km_7 = km;
else if (column_count = 8) then km_8 = km;
else if (column_count = 9) then km_9 = km;
else if (column_count = 10) then km_10 = km;
if (column_count < 10) then
column_count = column_count + 1;
else
begin
-- row complete, output
column_count = 1;
suspend;
end
end
if (column_count > 1) then
begin
-- partial row
while (column_count <= 10) do
begin
-- null remaining columns
if (column_count = 2) then km_2 = null;
else if (column_count = 3) then km_3 = null;
else if (column_count = 4) then km_4 = null;
else if (column_count = 5) then km_5 = null;
else if (column_count = 6) then km_6 = null;
else if (column_count = 7) then km_7 = null;
else if (column_count = 8) then km_8 = null;
else if (column_count = 9) then km_9 = null;
else if (column_count = 10) then km_10 = null;
column_count = column_count + 1;
end
-- output partial row
suspend;
end
end
在 Firebird 4.0 中,您可以使用 window 函数实现相同的结果。
with col_row as (
select
km,
mod(row_number() over(order by km) - 1, 10) as column_group,
(row_number() over(order by km) - 1) / 10 row_group
from kms
)
select
min(km) filter (where column_group = 0),
min(km) filter (where column_group = 1),
min(km) filter (where column_group = 2),
min(km) filter (where column_group = 3),
min(km) filter (where column_group = 4),
min(km) filter (where column_group = 5),
min(km) filter (where column_group = 7),
min(km) filter (where column_group = 8),
min(km) filter (where column_group = 9)
from col_row
group by row_group
对于 Firebird 3.0,将 min(km) filter (where column_group = n)
替换为 min(decode(column_group, n, km))
或 min(case when column_group = n then km)
(其中 n 为 0、1、..、9)。
我有一个table包含几公里约100 table of kilometers
我需要像这样将行旋转成列 pivot rows into columns
- 列数固定在行数=10
- 公里可以重复,有差距,例如:263, 263, 264, 265, 270..
我想用“with recursive”,但是网上的例子很少( 如果您能帮我解决问题,我将不胜感激!
正如我在评论中提到的,这可能是在您的表示层中更好地解决的问题,而不是通过查询。我不确定这是否可以通过(递归)CTE 解决,但我可以使用 EXECUTE BLOCK
在 PSQL 中为您提供解决方案(这也可以以存储过程的形式完成)。
此解决方案将行映射到列,并在所有列都已填充后开始新的一行。
execute block
returns (km_1 smallint, km_2 smallint, km_3 smallint, km_4 smallint, km_5 smallint,
km_6 smallint, km_7 smallint, km_8 smallint, km_9 smallint, km_10 smallint)
as
declare column_count smallint = 1;
declare km smallint;
begin
for select km from kms order by km into km do
begin
-- map value to column
if (column_count = 1) then km_1 = km;
else if (column_count = 2) then km_2 = km;
else if (column_count = 3) then km_3 = km;
else if (column_count = 4) then km_4 = km;
else if (column_count = 5) then km_5 = km;
else if (column_count = 6) then km_6 = km;
else if (column_count = 7) then km_7 = km;
else if (column_count = 8) then km_8 = km;
else if (column_count = 9) then km_9 = km;
else if (column_count = 10) then km_10 = km;
if (column_count < 10) then
column_count = column_count + 1;
else
begin
-- row complete, output
column_count = 1;
suspend;
end
end
if (column_count > 1) then
begin
-- partial row
while (column_count <= 10) do
begin
-- null remaining columns
if (column_count = 2) then km_2 = null;
else if (column_count = 3) then km_3 = null;
else if (column_count = 4) then km_4 = null;
else if (column_count = 5) then km_5 = null;
else if (column_count = 6) then km_6 = null;
else if (column_count = 7) then km_7 = null;
else if (column_count = 8) then km_8 = null;
else if (column_count = 9) then km_9 = null;
else if (column_count = 10) then km_10 = null;
column_count = column_count + 1;
end
-- output partial row
suspend;
end
end
在 Firebird 4.0 中,您可以使用 window 函数实现相同的结果。
with col_row as (
select
km,
mod(row_number() over(order by km) - 1, 10) as column_group,
(row_number() over(order by km) - 1) / 10 row_group
from kms
)
select
min(km) filter (where column_group = 0),
min(km) filter (where column_group = 1),
min(km) filter (where column_group = 2),
min(km) filter (where column_group = 3),
min(km) filter (where column_group = 4),
min(km) filter (where column_group = 5),
min(km) filter (where column_group = 7),
min(km) filter (where column_group = 8),
min(km) filter (where column_group = 9)
from col_row
group by row_group
对于 Firebird 3.0,将 min(km) filter (where column_group = n)
替换为 min(decode(column_group, n, km))
或 min(case when column_group = n then km)
(其中 n 为 0、1、..、9)。