汇总行中的唯一列
Summarize unique column in row
我是 Firebird 的新手,需要您的帮助。
我有一个具有以下减少输出的存储过程:
Player
Team
Number
Reus
Ahlen
18
Lewandowski
Posen
19
Reus
MG
11
Reus
BVB
11
Lewandowski
BVB
9
Haaland
BVB
9
我想总结一下球员,把Team&Number改成一个新的列。
输出应该是:
Player
Station 1
Station 2
Station 3
Reus
Ahlen 18
MG 11
BVB 11
Lewandowski
Posen 19
BVB 9
Haaland
BVB 9
我正在使用 Firebird 2.5.8
对于此答案的其余部分,我使用以下设置:
create table player (
player varchar(100) not null,
team varchar(100) not null,
number smallint not null
);
commit;
insert into player (player, team, number) values ('Reus', 'Ahlen', 18);
insert into player (player, team, number) values ('Lewandowski', 'Posen', 19);
insert into player (player, team, number) values ('Reus', 'MG', 11);
insert into player (player, team, number) values ('Reus', 'BVB', 11);
insert into player (player, team, number) values ('Lewandowski', 'BVB', 9);
insert into player (player, team, number) values ('Haaland', 'BVB', 9);
commit;
示例假定玩家名称足以唯一标识玩家。
由于 Firebird 的 DSQL 方言的性质和查询执行的实现,'station' 列的数量是固定的。在此示例中,我使用了三个,就像您的问题一样,但如果需要,可以将其扩展到更多列。在 Firebird 2.5 中,生成所需的枢轴 table 很混乱,并且可能不会很好地执行。
一个基本的、纯粹的 SQL 解决方案,类似于:
with unique_players as (
select distinct player from player
)
select
player,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 1) as station_1,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 2 to 2) as station_2,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 3 to 3) as station_3
from unique_players;
在这个例子中,我们确定唯一玩家,然后select第一,第二和第三站使用子查询使用rows
(you can also use first
/skip
, or, in Firebird 3.0 and higher, offset
/fetch
)
另一种可能性能更好的方法是使用存储过程或执行块,但代码确实变得更复杂。
execute block
returns (
player type of column player.player,
station_1 varchar(120),
station_2 varchar(120),
station_3 varchar(120)
)
as
declare station smallint = 0;
declare current_player type of column player.player;
declare current_team type of column player.team;
declare current_number type of column player.number;
begin
for select player, team, number
from player
order by player, number desc
into current_player, current_team, current_number
do
begin
if (current_player is distinct from player) then
begin
-- output row when player changes
if (player is not null) then suspend;
station = 1;
player = current_player;
station_1 = current_team || ' ' || current_number;
end
else
begin
station = station + 1;
if (station = 2) then
begin
station_2 = current_team || ' ' || current_number;
end
else if (station = 3) then
begin
station_3 = current_team || ' ' || current_number;
end
-- rows for station > 3 are ignored
end
end
-- output final player
if (player is not null) then suspend;
end
这会遍历行,填充执行块的输出列,并在找到下一个玩家时输出它们。
另一方面,在 Firebird 4.0 中,您可以执行以下操作:
使用NTH_VALUEwindow函数:
select player, station_1, station_2, station_3
from (
select
player,
row_number() over player_order as rownum,
nth_value(team || number, 1) over player_order as station_1,
nth_value(team || number, 2) over player_order as station_2,
nth_value(team || number, 3) over player_order as station_3
from player
window player_order as (
partition by player
order by number desc
rows between unbounded preceding and unbounded following)
)
where rownum = 1
或使用filtered aggregate functions:
with player_stations as (
select
player,
team || ' ' || number as station,
row_number() over (partition by player order by number desc) as rownum
from player
)
select
player,
max(station) filter (where rownum = 1) as station_1,
max(station) filter (where rownum = 2) as station_2,
max(station) filter (where rownum = 3) as station_3
from player_stations
group by player
使用 lateral join:
with player_stations as (
select player, number, team || ' ' || number as station from player
)
select
player,
st1.station as station_1,
st2.station as station_2,
st3.station as station_3
from (select distinct player from player) p
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
fetch first row only
) st1 on true
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
offset 1 row
fetch next row only
) st2 on true
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
offset 2 rows
fetch next row only
) st3 on true
这与第一个示例类似,但将站的 selection 向下推入横向连接(Firebird 4.0 中引入的功能)。
我是 Firebird 的新手,需要您的帮助。
我有一个具有以下减少输出的存储过程:
Player | Team | Number |
---|---|---|
Reus | Ahlen | 18 |
Lewandowski | Posen | 19 |
Reus | MG | 11 |
Reus | BVB | 11 |
Lewandowski | BVB | 9 |
Haaland | BVB | 9 |
我想总结一下球员,把Team&Number改成一个新的列。
输出应该是:
Player | Station 1 | Station 2 | Station 3 |
---|---|---|---|
Reus | Ahlen 18 | MG 11 | BVB 11 |
Lewandowski | Posen 19 | BVB 9 | |
Haaland | BVB 9 |
我正在使用 Firebird 2.5.8
对于此答案的其余部分,我使用以下设置:
create table player (
player varchar(100) not null,
team varchar(100) not null,
number smallint not null
);
commit;
insert into player (player, team, number) values ('Reus', 'Ahlen', 18);
insert into player (player, team, number) values ('Lewandowski', 'Posen', 19);
insert into player (player, team, number) values ('Reus', 'MG', 11);
insert into player (player, team, number) values ('Reus', 'BVB', 11);
insert into player (player, team, number) values ('Lewandowski', 'BVB', 9);
insert into player (player, team, number) values ('Haaland', 'BVB', 9);
commit;
示例假定玩家名称足以唯一标识玩家。
由于 Firebird 的 DSQL 方言的性质和查询执行的实现,'station' 列的数量是固定的。在此示例中,我使用了三个,就像您的问题一样,但如果需要,可以将其扩展到更多列。在 Firebird 2.5 中,生成所需的枢轴 table 很混乱,并且可能不会很好地执行。
一个基本的、纯粹的 SQL 解决方案,类似于:
with unique_players as (
select distinct player from player
)
select
player,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 1) as station_1,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 2 to 2) as station_2,
(select team || ' ' || number
from player
where player = unique_players.player
order by number desc
rows 3 to 3) as station_3
from unique_players;
在这个例子中,我们确定唯一玩家,然后select第一,第二和第三站使用子查询使用rows
(you can also use first
/skip
, or, in Firebird 3.0 and higher, offset
/fetch
)
另一种可能性能更好的方法是使用存储过程或执行块,但代码确实变得更复杂。
execute block
returns (
player type of column player.player,
station_1 varchar(120),
station_2 varchar(120),
station_3 varchar(120)
)
as
declare station smallint = 0;
declare current_player type of column player.player;
declare current_team type of column player.team;
declare current_number type of column player.number;
begin
for select player, team, number
from player
order by player, number desc
into current_player, current_team, current_number
do
begin
if (current_player is distinct from player) then
begin
-- output row when player changes
if (player is not null) then suspend;
station = 1;
player = current_player;
station_1 = current_team || ' ' || current_number;
end
else
begin
station = station + 1;
if (station = 2) then
begin
station_2 = current_team || ' ' || current_number;
end
else if (station = 3) then
begin
station_3 = current_team || ' ' || current_number;
end
-- rows for station > 3 are ignored
end
end
-- output final player
if (player is not null) then suspend;
end
这会遍历行,填充执行块的输出列,并在找到下一个玩家时输出它们。
另一方面,在 Firebird 4.0 中,您可以执行以下操作:
使用NTH_VALUEwindow函数:
select player, station_1, station_2, station_3
from (
select
player,
row_number() over player_order as rownum,
nth_value(team || number, 1) over player_order as station_1,
nth_value(team || number, 2) over player_order as station_2,
nth_value(team || number, 3) over player_order as station_3
from player
window player_order as (
partition by player
order by number desc
rows between unbounded preceding and unbounded following)
)
where rownum = 1
或使用filtered aggregate functions:
with player_stations as (
select
player,
team || ' ' || number as station,
row_number() over (partition by player order by number desc) as rownum
from player
)
select
player,
max(station) filter (where rownum = 1) as station_1,
max(station) filter (where rownum = 2) as station_2,
max(station) filter (where rownum = 3) as station_3
from player_stations
group by player
使用 lateral join:
with player_stations as (
select player, number, team || ' ' || number as station from player
)
select
player,
st1.station as station_1,
st2.station as station_2,
st3.station as station_3
from (select distinct player from player) p
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
fetch first row only
) st1 on true
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
offset 1 row
fetch next row only
) st2 on true
left join lateral (
select station
from player_stations
where player = p.player
order by number desc
offset 2 rows
fetch next row only
) st3 on true
这与第一个示例类似,但将站的 selection 向下推入横向连接(Firebird 4.0 中引入的功能)。