I've got the following schema, which can not be modified since it's a problem taken from an exam:
Player ------- player_id (PK) player_name player_games_total player_games_won Competition ----------- comp_id (PK) comp_player1 (FK references Player.player_id, NOT NULL) comp_player2 (FK references Player.player_id, NULL) comp_player3 (FK references Player.player_id, NULL) comp_player4 (FK references Player.player_id, NULL) comp_player5 (FK references Player.player_id, NULL) comp_winner (integer from 1 to 5 or NULL, indicates which player, if any, won)
For example, the following row in the Competition table:
1 | 23 | 42 | NULL | NULL | NULL | 2
indicates that only players 23 and 42 participated in competition 1 and player 42 won.
The exercise stated:
A trigger needs to be created that updates
Player.player_games_total
andPlayer.player_games_won
with every new competition inserted inCompetitions
. The trigger should handle correctly individual INSERTs as well as bulkINSERT
s. In other words, don't assume theINSERT
ED table will contain only one row at any given time.
The solution I wrote is in the following paragraph, but first I'd like to make a few comments. Programming is not new to me but SQL is. I know about coding best practices and like to think that I can recognize good, clear code when I see it. I definitely don't like what I see in my solution, but I don't have enough experience with SQL to know whether it's because of my own limitations with the language or because the schema is not ideal and is forcing me to make queries like this.
CREATE TRIGGER [dbo].[tr_aff_ins_competitions]
ON [dbo].[COMPETITIONS]
AFTER INSERT
AS BEGIN
-- This is the part of the trigger that updates 'player_games_total' values
update dbo.Player
set player_games_total = player_games_total + ( select count(comp_player1)
from inserted
where Player.player_id = inserted.comp_player1)
where Player.player_id IN (select comp_player1 from inserted)
update dbo.Player
set player_games_total = player_games_total + ( select count(comp_player2)
from inserted
where Player.player_id = inserted.comp_player2)
where Player.player_id IN (select comp_player2 from inserted)
update dbo.Player
set player_games_total = player_games_total + ( select count(comp_player3)
from inserted
where Player.player_id = inserted.comp_player3)
where Player.player_id IN (select comp_player3 from inserted)
update dbo.Player
set player_games_total = player_games_total + ( select count(comp_player4)
from inserted
where Player.player_id = inserted.comp_player4)
where Player.player_id IN (select comp_player4 from inserted)
update dbo.Player
set player_games_total = player_games_total + ( select count(comp_player5)
from inserted
where Player.player_id = inserted.comp_player5)
where Player.player_id IN (select comp_player5 from inserted)
-- This is the part of the trigger that updates 'player_games_won' values
update dbo.Player
set player_games_won = player_games_won + ( select COUNT(winner)
from dbo.COMPETITIONS comp_sub
where comp_sub.winner = 1
and comp_sub.comp_player1 = player_id)
where Player.player_id IN (select comp_player1 from inserted)
update dbo.Player
set player_games_won = player_games_won + ( select COUNT(winner)
from dbo.COMPETITIONS comp_sub
where comp_sub.winner = 2
and comp_sub.comp_player2 = player_id)
where Player.player_id IN (select comp_player2 from inserted)
update dbo.Player
set player_games_won = player_games_won + ( select COUNT(winner)
from dbo.COMPETITIONS comp_sub
where comp_sub.winner = 3
and comp_sub.comp_player3 = player_id)
where Player.player_id IN (select comp_player3 from inserted)
update dbo.Player
set player_games_won = player_games_won + ( select COUNT(winner)
from dbo.COMPETITIONS comp_sub
where comp_sub.winner = 4
and comp_sub.comp_player4 = player_id)
where Player.player_id IN (select comp_player4 from inserted)
update dbo.Player
set player_games_won = player_games_won + ( select COUNT(winner)
from dbo.COMPETITIONS comp_sub
where comp_sub.winner = 5
and comp_sub.comp_player5 = player_id)
where Player.player_id IN (select comp_player5 from inserted)
END