regrouping all results in a select with a while

生来就可爱ヽ(ⅴ<●) 提交于 2020-12-27 06:21:16

问题


I'm doing some request to help a game dev to balance his game, i'm trying to see how many player use what rune, and at what average level

here is my code :

declare @runeID varchar(100)
set @runeID=22001

select counT(i.characterid) as 'user level 1 to 10', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>0 and level<11 and attached>0
select counT(i.characterid) as 'user level 11 to 20', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>10 and level<21 and attached>0
select counT(i.characterid) as 'user level 21 to 30', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>20 and level<31 and attached>0
select counT(i.characterid) as 'user level 31 to 40', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>30 and level<41 and attached>0
select counT(i.characterid) as 'user level 41 to 50', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>40 and level<51 and attached>0
select counT(i.characterid) as 'user level 51 to 60', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>50 and level<61 and attached>0
select counT(i.characterid) as 'user level 61 to 70', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>60 and level<71 and attached>0
select counT(i.characterid) as 'user level 71 to 80', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>70 and level<81 and attached>0
select counT(i.characterid) as 'user level 81 to 90', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>80 and level<91 and attached>0
select counT(i.characterid) as 'user level 91 to 100', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>90 and level<101 and attached>0
select counT(i.characterid) as 'user level 101 to 110', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>100 and level<111 and attached>0
select counT(i.characterid) as 'user level 111 to 120', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>110 and level<121 and attached>0
select counT(i.characterid) as 'user level 121 to 130', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>120 and level<131 and attached>0
select counT(i.characterid) as 'user level 131+', avg(i.maxUpgrade) as 'average level' from items i inner join characters c on i.characterId=c.characterId 
        where itemId=@runeID and level>130 and attached>0

This code give me usage of the rune i select in my variable each 10 levels. I got this code from someone else helping me (Gordon Linoff):

select floor(level / 10) * 10 as range_start,
avg(i.maxUpgrade) as avg_level,
count(i.characterId) as number_of_user
from items i inner join
characters c
on i.characterId = c.characterId
where attached > 0
group by floor(level / 10) * 10
order by range_start ASC

this code shorten what i done and i was wondering if I could use a while to create new column for each runeId I put before in a list (12001,12002,12002,etc...), so I could get something like that :

              22001_use   22001_avg_lvl    22002_use    22002_avg_lvl
level_1-9               
level_10-19             
level_20-29             
                        

so in in first column an indicator for level range, 2nd and 3rd column the number of player playing that rune each 10 levels according to first column, and the average level peoples use that rune, each rune in the list create 2 new column for use and avg level

So this way if me or the dev need the most recent stats, he just have to run the query, copy the result and past it in a google sheet, also with the list if he decides to add more runes it would be easier to update the code


回答1:


I think you want conditional aggregation:

select 
    floor(level / 10) * 10 as range_start,
    sum(case when i.itemid = 22001 then 1 else 0 end) as use_22001
    avg(case when i.itemid = 22001 then i.maxUpgrade end) as avg_lvl_22001,
    sum(case when i.itemid = 22002 then 1 else 0 end) as use_22002
    avg(case when i.itemid = 22002 then i.maxUpgrade end) as avg_lvl_22002
from items i 
inner join characters c on i.characterId = c.characterId
where attached > 0 and i.item_id in (22001, 22002)
group by floor(level / 10) * 10
sort by range_start ASC



回答2:


Here's an attempt to refactor the code. Since 'level' is an integer (from the characters table) there's no need to take the FLOOR. Eliminating that and removing the calculation to a CROSS APPLY'ed virtual table and column 'lvl.lvl'. Then for some reason there's a 'sort by' in the code when it should be ORDER BY. Also, there were some missing commas. Something like this.

select lvl.lvl as range_start,
       sum(case when i.itemid = 22001 then 1 else 0 end) as use_22001, avg(case when i.itemid = 22001 then i.maxUpgrade end) as avg_lvl_22001,
       sum(case when i.itemid = 22002 then 1 else 0 end) as use_22002, avg(case when i.itemid = 22002 then i.maxUpgrade end) as avg_lvl_22002,
       avg(i.maxUpgrade) as tot_avg_level,
       count(i.characterId) as tot_num_users
from items i 
     join characters c on i.characterId = c.characterId
     cross apply (select (c.[level]/10)*10 lvl) lvl
where attached > 0
group by lvl.lvl
order by lvl.lvl;

To build the SQL dynamically so that it creates the 2 columns for each rune (represented by an itemid) in the items table, something like this

declare
  @select         nvarchar(max)=N'select lvl.lvl as range_start, ',
  @str1           nvarchar(max)=N' sum(case when i.itemid = ',
  @str2           nvarchar(max)=N' then 1 else 0 end) as use_',
  @str3           nvarchar(max)=N', avg(case when i.itemid = ',
  @str4           nvarchar(max)=N' then i.maxUpgrade end) as avg_lvl_',
  @str5           nvarchar(max)=N',',
  @from           nvarchar(max)=N' avg(i.maxUpgrade) as tot_avg_level,
                                   count(i.characterId) as tot_num_users
                            from items i 
                                    join characters c on i.characterId = c.characterId
                                    cross apply (select (c.[level]/10)*10 lvl) lvl
                            where attached > 0
                            group by lvl.lvl
                            order by lvl.lvl;',
  @sql            nvarchar(max);

select @sql=concat(@select,
                   string_agg(concat(@str1, cast(itemid as char(5)), 
                                     @str2, cast(itemid as char(5)), 
                                     @str3, cast(itemid as char(5)), 
                                     @str4, cast(itemid as char(5)), 
                                     @str5),
                   @from)
from items
where itemid>22000 
      and itemid<24000;

exec sp_executesql @sql;



来源:https://stackoverflow.com/questions/64448191/regrouping-all-results-in-a-select-with-a-while

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!