【问题标题】:Group by a set of data and order items in each part separately from other parts in T SQL在 T SQL 中按一组数据分组,并在每个部分中与其他部分分开排序项目
【发布时间】:2017-11-20 09:19:45
【问题描述】:

我有一组数据,其中包含 2 个字段“ActivationTime”,即 DATETIME 类型和“Score”,即 INT 类型。

我想按照这个规则对所有数据进行分组:

(1) 每组数据之间必须有最大5天的差异(对应于“ActivationTime”值。注意第一个“ActivationTime”是一组数据中最新的“ActivationTime”。例如在下面示例第一个“ActivationTime”将为“2017-11-24 09:45:00.000”,其得分 = 1)

(2) 分组数据各部分中的项目必须按“分数”值与其他分组数据部分“分开”排序

如果可以的话,有人可以帮助我吗?

编辑:例如想象@ExampleTabel 如下:

Score                  ActivationTime
-------------------------------------------
  9               '2017-11-20 09:37:00.000'
  5               '2017-11-21 09:39:00.000'
  4               '2017-11-22 09:40:00.000'
  3               '2017-11-23 09:43:00.000'
  1               '2017-11-24 09:45:00.000'
  12              '2017-11-22 09:49:00.000'
  7               '2017-11-17 09:38:00.000'
  2               '2017-11-15 09:41:00.000'
  0               '2017-11-14 09:44:00.000'
  15              '2017-11-13 09:47:00.000'
  7               '2017-11-12 09:46:00.000'
  20              '2017-11-11 09:42:00.000'
  4               '2017-11-10 09:78:00.000'

我除了要生成的结果:

Score                 ActivationTime             Category
---------------------------------------------------------------
  12             '2017-11-20 09:49:00.000'          1
  9              '2017-11-20 09:37:00.000'          1
  5              '2017-11-21 09:39:00.000'          1
  4              '2017-11-22 09:40:00.000'          1
  3              '2017-11-23 09:43:00.000'          1
  1              '2017-11-24 09:45:00.000'          1

  15             '2017-11-13 09:47:00.000'          2
  7              '2017-11-17 09:38:00.000'          2
  2              '2017-11-15 09:41:00.000'          2
  0              '2017-11-14 09:44:00.000'          2

  20             '2017-11-11 09:42:00.000'          3
  7              '2017-11-12 09:46:00.000'          3
  3              '2017-11-20 09:37:57.570'          3
  4              '2017-11-10 09:78:00.000'          3

【问题讨论】:

  • 所以您想要每天的前 5 名分数,按分数排序?
  • 不,我想订购与其他组部分分开的组部分中存在的所有数据,我也不想获得任何前 N 分。我的意思是首先按“ActivationTime”排序,然后按“Score”排序,但查询结果必须在其时间组中切片。
  • 你的问题很不清楚。你想要什么?如果您只是想按您的组进行切片,请使用 CTE,然后按分数和激活时间排序。

标签: sql-server tsql group-by sql-order-by


【解决方案1】:

从你所说的来看,你似乎想要这样的东西。

select
Score, ActivationTime, (rnk - 1) / 5 grp
from (
    select
        Score, ActivationTime, dense_rank()over(order by cast(ActivationTime as date) desc) rnk
from
    mytable
) t
order by grp, Score desc

你应该给出一些样本数据和你期望得到更好的帮助的结果

【讨论】:

    【解决方案2】:

    根据您的 cmets,这是您在 N 天后执行此操作的方式。

    首先,我创建一个虚拟表,其中包含我想返回多少天的数字。然后我在我的光标中循环这个表来创建我的 CTE 语句。最后我合并我所有的 CTE,然后按激活时间和分数对它们进行排序

    /*SCRIPT */
    
    DECLARE @NDaysAgo nvarchar(2) = 20 --Change this based on how many days you want to go back
    DECLARE @Number nvarchar(2)
    DECLARE @sqlCreateNumbers nvarchar(max)
    DECLARE @AliasName nvarchar(50)
    DECLARE @SQL nvarchar(max)
    DECLARE @SQLUnion nvarchar(max)
     DECLARE @crlf nvarchar(max)
     SET @crlf = CHAR(13)
    DECLARE @SQLTotal nvarchar(MAX)
    
    Set @sqlCreateNumbers = '
    
    IF EXISTS (SELECT * FROM sys.objects 
    WHERE object_id = OBJECT_ID(N''[dbo].[numbers]'') AND type in (N''U''))
    DROP TABLE [dbo].[numbers];
    
    SELECT TOP '+@NDaysAgo+' IDENTITY(int,0,1) AS n 
    into dbo.numbers
    FROM MASTER..spt_values a, MASTER..spt_values b;
    
    CREATE UNIQUE CLUSTERED INDEX idx_1 ON numbers(n);
    
    
    '
    PRINT @sqlCreateNumbers
    
    EXEC (@sqlCreateNumbers)
    
    
    DECLARE SqlCur CURSOR FOR
    Select DaysAgo = N,Alias = 'Today'+cast(N as nvarchar(50))
    from dbo.Numbers
    OPEN SqlCur
    FETCH NEXT FROM SqlCur
    INTO @Number,@AliasName
    IF (@@FETCH_STATUS>=0)
    BEGIN
    SET @SQL = 'with '+@AliasName+' as (
    Select '''+@AliasName+''' as SourceName,Score,ActivationTime
    from dbo.testactivation
    Where cast(ActivationTime as date) = cast(dateadd(dd,'+@Number+',GETDATE()) as date)
    
    )'
    
    SET @SQLUnion = 'Select * from '+@AliasName+''
    
    --PRINT @SQL
    FETCH NEXT FROM SqlCur INTO @Number,@AliasName
     END
     WHILE (@@FETCH_STATUS<>-1)
    
     BEGIN
     IF (@@FETCH_STATUS<>-2)
    
     SET @SQL = @SQL + ','+@AliasName+' as (
    Select '''+@AliasName+''' as SourceName,Score,ActivationTime
    from dbo.testactivation
    Where cast(ActivationTime as date) = cast(dateadd(dd,-'+@Number+',GETDATE()) as date)
    
    )'
    SET @SQLUnion =  @SQLUnion + @crlf+ ' union all Select * from '+@AliasName+''
    --PRINT @SQL
    
    FETCH NEXT FROM SqlCur INTO @Number,@AliasName
    END
    
     CLOSE SqlCur
     DEALLOCATE SqlCur
    
    
    SET @SQLTotal = @SQL + 'Select * from ( '+@SQLUnion+ ' ) x ORDER BY ACTIVATIONTIME DESC, SCORE DESC'
    
    PRINT @SQLTotal --This will not show you all records since there is a limit to how much text it can show
    Select @SQLTotal -- If you select it you can see the query
    
    EXEC(@SQLTotal) --This will execute your statement, so you can see your descired result
    

    编辑 如果您无法使用无法获得 NDays 的变量,则必须对其进行硬编码。

    一次查询

    Select 'Data' as SourceName,Score,ActivationTime
    from dbo.testactivation
    Where cast(ActivationTime as date) between cast(dateadd(dd,0,GETDATE()) as date)
    and cast(dateadd(dd,-20,GETDATE()) as date)
    order by ActivationTime desc,score desc
    

    结果

    【讨论】:

    • 我不想对 SUM(score) 做任何事情,但我想查询“Score”字段。 “今天的日期”也表示今天的日期,例如“2017-11-20 09:37:57.570”,它不是别名。
    • 什么?为什么不直接选择数据并按分数和激活时间排序?
    • 它适用于具有“ActivationTime”
    • @MiladRashidi 很好,我现在让它变得动态,所以你可以在 N 天前选择
    • 在我的情况下,根据您的回复,我很难得到@NDaysAgo。如果可能,请以其他方式帮助我。我应该只在一个查询中获得结果。
    猜你喜欢
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 2015-11-21
    • 2016-03-12
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多