taiko
taiko

Reputation: 478

Sql - loop through two tables and sum a value based on condition

I'm working on a project for a betting program (point based) and if need to create a stored procedure on sql server that does the following:

I've been searching forever on a way to do this but I can't figure out a way. It may well be a noobish question, be we all have to start somewhere. I thought about looping, which is theoretically what I need to do but I need to iterate through each row from the bets table and compare its values with the values of each row of the games table.

It'd be great if you could help me. Thanks.

EDIT: Oh, shoot. Sorry, I was about to add the tables and I forgot. Well, here they are:

-Bets table:

CREATE TABLE Bets(
   id_bet        NUMERIC(18,0) NOT NULL PRIMARY KEY 
  ,id_user       NUMERIC(18,0)
  ,id_game       NUMERIC(18,0)
  ,date          NUMERIC(8,0)
  ,time          NUMERIC(4,0)
  ,goals_home    NUMERIC(18,0)
  ,goals_visitor NUMERIC(18,0)
);
INSERT INTO Bets(id_bet,id_user,id_game,date,time,goals_home,goals_visitor) VALUES (1,1,4,20170614,1600,1,1);
INSERT INTO Bets(id_bet,id_user,id_game,date,time,goals_home,goals_visitor) VALUES (2,1,3,20170614,1600,1,1);
INSERT INTO Bets(id_bet,id_user,id_game,date,time,goals_home,goals_visitor) VALUES (3,7,3,20170614,1600,1,1);
INSERT INTO Bets(id_bet,id_user,id_game,date,time,goals_home,goals_visitor) VALUES (4,7,4,20170614,1600,1,1);

-Games table:

CREATE TABLE Games(
   id_game         NUMERIC(18,0) NOT NULL PRIMARY KEY 
  ,num_game        NUMERIC(18,0)
  ,id_club_home    NUMERIC(18,0)
  ,id_club_visitor NUMERIC(18,0)
  ,id_competition  NUMERIC(18,0)
  ,goals_home      NUMERIC(18,0)
  ,goals_visitor   NUMERIC(18,0)
  ,date            NUMERIC(8,0)
  ,time            NUMERIC(4,0)
);
INSERT INTO Games(id_game,num_game,id_club_home,id_club_visitor,id_competition,goals_home,goals_visitor,date,time) VALUES (1,1,3,6,2,2,2,20170614,1700);
INSERT INTO Games(id_game,num_game,id_club_home,id_club_visitor,id_competition,goals_home,goals_visitor,date,time) VALUES (3,2,4,3,2,1,3,20170614,1800);
INSERT INTO Games(id_game,num_game,id_club_home,id_club_visitor,id_competition,goals_home,goals_visitor,date,time) VALUES (4,3,3,4,2,1,3,20170614,1800);
INSERT INTO Games(id_game,num_game,id_club_home,id_club_visitor,id_competition,goals_home,goals_visitor,date,time) VALUES (5,4,6,3,2,2,3,20170614,1800);
INSERT INTO Games(id_game,num_game,id_club_home,id_club_visitor,id_competition,goals_home,goals_visitor,date,time) VALUES (6,5,4,6,2,NULL,NULL,20170614,1600);

-I've tried this (and other ways but didn't save them):

CREATE PROCEDURE [dbo].[Count_Points] @valor AS INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @a AS INT
    DECLARE @goals_home_bet AS NUMERIC(18, 0) = (
            SELECT Bets.goals_home
            FROM Bets
            INNER JOIN Games ON Bets.id_game = Games.id_game
            )
    DECLARE @goals_visitor_bet AS NUMERIC(18, 0) = (
            SELECT Bets.goals_visitor
            FROM Bets
            INNER JOIN Games ON Bets.id_game = Games.id_game
            )
    DECLARE @goals_home_games AS NUMERIC(18, 0) = (
            SELECT Games.goals_home
            FROM Bets
            INNER JOIN Games ON Bets.id_game = Games.id_game
            )
    DECLARE @goals_visitor_games AS NUMERIC(18, 0) = (
            SELECT Games.goals_visitor
            FROM Bets
            INNER JOIN Games ON Bets.id_game = Games.id_joid_gamego
            )

    SET @valor = 0
    SET @a = 1
    SET @valor = sum(@valor + 3)

    WHILE (
            (
                SELECT max(id_bet)
                FROM Bets
                ) > @a
            )
    BEGIN
        SET @a += 1
    END
END

It's just for testing to see if it worked (hence referencing the value 3 only), but apparently I get a value of 3 only. The other ways I'd also get 3 or null, even.

EDIT 2: My solution (probably not the most efficient, but still):

CREATE PROCEDURE [dbo].[Calculate_Points]
        @control as int output,
        @points as int output,
        @nickname varchar(50)

AS
BEGIN

    SET NOCOUNT ON;

    declare @cont numeric(18,0)=1
    declare @cont1 numeric(18,0)
    declare @id_user numeric(18,0)=(select num_user from Users where nickname=@nickname)
    declare @id_game numeric(18,0)
    declare @goals_home_bet numeric(18,0)
    declare @goals_visitor_bet numeric(18,0)
    declare @goals_home_game numeric(18,0)
    declare @goals_visitor_game numeric(18,0)
    set @points=0


    while(@cont<=(select max(num_bet) from Bets))
    begin
        if exists (select id_user from Bets where @id_user=id_user and num_bet=@cont)
        begin
            set @id_game=(select id_game from Bets where num_bet=@cont)
            set @goals_home_bet=(select goals_home from Bets where num_bet=@cont)
            set @goals_visitor_bet=(select goals_visitor from Bets where num_bet=@cont)
            set @cont1=1
            while(@cont1<(select max(id_game) from Games))
            begin
                if(@id_game=(select id_game from Games where id_game =@cont1))
                begin
                    set @goals_home_game=(select goals_home from Games where num_game=@cont1)
                    set @goals_visitor_game=(select goals_visitor from Games where num_game=@cont1)

                    if(@goals_home_bet=@golos_casa_jogo and @golos_fora_aposta=@golos_fora_jogo)
                        set @pontos+=3
                    else if((@goals_home_bet>@goals_visitor_bet and @goals_home_game>@goals_visitor_game) or (@goals_home_bet<@goals_visitor_bet and @goals_home_game<@goals_visitor_bet) or (@goals_home_bet=@goals_visitor_bet and @goals_home_game=@goals_visitor_bet))
                        set @points+=1
                end

                set @cont1+=1
            end
        end
        set @cont+=1
    end

END

Upvotes: 3

Views: 729

Answers (1)

S.C.
S.C.

Reputation: 1160

Switch from bit to int for your goals and then try something like this:

create view vUserPointsPerGame
as
select
    id_user, bets.id_game,
    case 
        -- you could also just compare the goal differences if you want
        when bets.goals_home = games.goals_home and bets.goals_visitor = games.goals_visitor then 3
        when (bets.goals_home >= bets.goals_visitor and games.goals_home >= games.goals_visitor) or (bets.goals_home < bets.goals_visitor and games.goals_home < games.goals_visitor) then 1        
        else 0
    end as Points
from
    bets
    join games on bets.id_game = games.id_game

go

create view vUserTotalPoints
as
    select id_user, sum(points) as TotalPoints 
    from vUserPointsPerGame 
    group by id_user
go

select * from vUserTotalPoints

That will return you a sum of points across all bets broken down by user.

You can make this more efficient, but the main idea here is that you don't need loops or stored procedures to do what you want to accomplish here.

Edit: You mentioned you wanted a procedure since it's easier for you to consume. Here's one that will get the total points for a single user:

create procedure spGetUserTotalPoints
(
    @iUserId int,
    @oTotalPoints int output
)
as
begin
    select @oTotalPoints = TotalPoints
    from vUserTotalPoints
    where id_user = @iUserId
end

And here's another that will get the total points for each user for all known users:

create procedure spGetUsersTotalPoints
as
begin
    select id_user, TotalPoints
    from vUserTotalPoints
end

Again, if you're getting errors about batches, just run each statement one at a time instead of relying on the go keyword. Some SQL front-ends don't like that.

Upvotes: 1

Related Questions