Kris Nobels
Kris Nobels

Reputation: 1987

Get Max(value) without grouping in SQL Server

I have this grouping problem that I do not need.

Here is my SQL code to create and seed the table:

create table player 
(
    playerid int identity(1,1) primary key,
    Name varchar(255)
)

create table gameplay
(
    gameplayid int identity(1,1) primary key,
    Name varchar(255),
    playerid int references player(playerid)
)

Create table room
(
    Roomid int identity(1,1) primary key,
    number int
)

Create table PC
(
    PCid int identity(1,1) primary key,
    Name varchar(255)
)

Create table playperiod
(
    PKid int identity(1,1) primary key,
    StartDate Datetime null,
    EndDate Datetime null,
    Roomid int references room(roomid),
    PCID int references PC(PCid),
    gameplayid int references gameplay(gameplayid)
)

Insert into player (name) values ('Kris')
Insert into player (name) values ('Bart')
Insert into player (name) values ('Bob')
Insert into player (name) values ('John')
Insert into player (name) values ('Iris')

insert into room (number) values (1000)
insert into room (number) values (1001)
insert into room (number) values (1002)
insert into room (number) values (1003)
insert into room (number) values (1004)
insert into room (number) values (1005)
insert into room (number) values (1006)
insert into room (number) values (1007)
insert into room (number) values (1008)
insert into room (number) values (1009)
insert into room (number) values (1010)

insert into gameplay (name, playerid) values ('WOW', 1)
insert into gameplay (name, playerid) values ('LOL', 2)
insert into gameplay (name, playerid) values ('DIablo', 3)
insert into gameplay (name, playerid) values ('Starcraft', 4)
insert into gameplay (name, playerid) values ('Borderlands', 5)

insert into PC (name) values ('Dell (1)')
insert into PC (name) values ('HP (1)')
insert into PC (name) values ('Dell (2)')
insert into PC (name) values ('HP (2)')
insert into PC (name) values ('Dell (3)')
insert into PC (name) values ('HP (3)')
insert into PC (name) values ('Dell (4)')
insert into PC (name) values ('HP (4)')
insert into PC (name) values ('Dell (5)')
insert into PC (name) values ('HP (5)')
insert into PC (name) values ('Dell (6)')
insert into PC (name) values ('HP (6)')
insert into PC (name) values ('Dell (7)')
insert into PC (name) values ('HP (7)')
insert into PC (name) values ('Dell (8)')
insert into PC (name) values ('HP (8)')
insert into PC (name) values ('Dell (9)')
insert into PC (name) values ('HP (9)')
insert into PC (name) values ('Dell (10)')
insert into PC (name) values ('HP (10)')

truncate table playperiod

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 10:02:00.000', '2015-01-22 11:30:00.000', 1, 1, 1)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid)   
values ('2015-01-22 10:02:00.000', '2015-01-22 16:02:00.000', 1, 2, 2)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 10:04:00.000', '2015-01-28 10:02:00.000', 2, 3, 3)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-20 10:02:00.000', '2015-01-22 10:02:00.000', 2, 4, 4)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 22:40:00.000', '2015-01-22 22:50:00.000', 3, 5, 1)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 22:55:00.000', '2015-01-22 23:50:00.000', 3, 6, 1)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 11:30:00.000', '2015-01-22 13:30:00.000', 1, 1, 1)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 14:30:00.000', '2015-01-22 16:30:00.000', 1, 1, 1)

insert into playperiod (StartDate, EndDate, Roomid, PCID, gameplayid) 
values ('2015-01-22 19:30:00.000', '2015-01-22 22:30:00.000', 1, 1, 1)

Know these are my queries:

Step 1) get everything for 1 day (No problem so far)

Select startdate, number, pc.name, gp.Name,p.Name  
from playperiod PD
left join room R on R.Roomid = PD.Roomid
left join pc on pc.PCid = PD.PCID
left join gameplay gp on GP.gameplayid = PD.gameplayid
left join player P on P.playerid = GP.playerid 
where 
DATEDIFF(day, pd.startdate, '2015-01-22') >= 0 and DATEDIFF(day, pd.startdate, '2015-01-22') <= 0

enter image description here

Step 2) Get the max date value from start date (Problem constation)

Select max(startdate) as startdate, number, pc.name, gp.Name,p.Name  
from playperiod PD
left join room R on R.Roomid = PD.Roomid
left join pc on pc.PCid = PD.PCID
left join gameplay gp on GP.gameplayid = PD.gameplayid
left join player P on P.playerid = GP.playerid 
where 
DATEDIFF(day, pd.startdate, '2015-01-22') >= 0 and DATEDIFF(day, pd.startdate, '2015-01-22') <= 0
group by number, pc.name, gp.Name,p.Name

enter image description here

At the end I do group by so the behavior is correct. But here the user 'Kris' plays on 3 Pc that day in 2 rooms.

But I would like to have this situation:

Here is the result that I need:

enter image description here

Can anyone help me ?

Upvotes: 2

Views: 446

Answers (2)

Dmitrij Kultasev
Dmitrij Kultasev

Reputation: 5745

You can read about row_number. Basically it assign number by some criteria. Here I said that make numbering for every group combination of gp.Name, P.Name and then I ordered these groups by datetime and took the latest one.

SELECT
    startdate ,
    number ,
    pc_name ,
    gp_name ,
    Name
FROM
    (
      SELECT
        startdate ,
        number ,
        pc.name pc_name ,
        gp.Name gp_name ,
        P.Name ,
        ROW_NUMBER() OVER ( PARTITION BY gp.Name, P.Name ORDER BY startdate DESC ) rn
      FROM
        playperiod PD
        LEFT JOIN room R ON R.Roomid = PD.Roomid
        LEFT JOIN pc ON pc.PCid = PD.PCID
        LEFT JOIN gameplay gp ON gp.gameplayid = PD.gameplayid
        LEFT JOIN player P ON P.playerid = gp.playerid
      WHERE
            DATEDIFF(DAY, PD.startdate, '2015-01-22') >= 0
        AND DATEDIFF(DAY, PD.startdate, '2015-01-22') <= 0
    ) a
WHERE
    rn = 1

Upvotes: 4

Steve Kass
Steve Kass

Reputation: 7184

You can do this a tiny bit more compactly with the nonstandard TOP WITH TIES clause:

SELECT TOP (1) WITH TIES
  startdate ,
  number ,
  pc.name pc_name ,
  gp.Name gp_name ,
  P.Name
FROM
  playperiod PD
  LEFT JOIN room R ON R.Roomid = PD.Roomid
  LEFT JOIN pc ON pc.PCid = PD.PCID
  LEFT JOIN gameplay gp ON gp.gameplayid = PD.gameplayid
  LEFT JOIN player P ON P.playerid = gp.playerid
WHERE PD.startdate >= '20150122'
AND PD.startdate < DATEADD(DAY,1,'20150122')
ORDER BY ROW_NUMBER() OVER (
  PARTITION BY gp.Name, P.Name
  ORDER BY startdate DESC
)

Upvotes: 2

Related Questions