SQL查询分组和日期时间差异

时间:2018-08-11 10:55:16

标签: sql sql-server

我对查询与特定参数的分组(或相交?)感到困惑。

我有一个带有用户活动周期的表和一个带有周期的表。

我需要查询以秒(或分钟)为单位的汇总表,该用户在每个期间都处于活动状态。并将结果插入到另一个表中。

类似于“插入...选择...分组依据”之类的东西。

用户活动表:

UserId  DatetimeFrom       DatetimeTo        
1       2018-01-01 10:00   2018-01-01 11:30  
1       2018-01-01 13:45   2018-01-01 14:20  
2       2018-01-01 10:50   2018-01-01 11:30

期间表:

PeriodId  DatetimeFrom       DatetimeTo        
1         2018-01-01 09:30   2018-01-01 10:15  
2         2018-01-01 10:15   2018-01-01 11:10  
3         2018-01-01 11:10   2018-01-01 12:00
4         2018-01-01 12:00   2018-01-01 13:30
5         2018-01-01 13:30   2018-01-01 15:00

需要结果表:

UserId  PeriodId  SumMinutes
1       1         15         //from 10:00 to 10:15 - period 1
1       2         55         //from 10:15 to 11:10 - period 2 
1       3         20         //etc
1       5         35
2       2         20
2       3         20

谢谢!

UPD:谢谢大家!所有答案都是有用的。

4 个答案:

答案 0 :(得分:0)

您正在寻找重叠的时间段-然后将它们加起来。如果满足以下条件,则两个周期重叠:

  • 第一个开始,第二个结束。
  • 第一个在第二个开始之后结束。

然后,您可以通过查看开始时间的最大值和结束时间的最小值来计算重叠的持续时间。

SQL最终看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"Files/plain_32m.tsv";
        static void Main(string[] args)
        {
            int rowCount = 0;
            StreamReader reader = new StreamReader(FILENAME);
            string line = "";
            DataTable dt = new DataTable();
            while ((line = reader.ReadLine()) != null)
            {
                string[] tsv = line.Split(new char[] { '\t' }).ToArray();
                //remove any end spaces from data
                tsv = tsv.Select(x => x.Trim()).ToArray();

                if (++rowCount == 1)
                {
                    foreach (string colName in tsv)
                    {
                        dt.Columns.Add(colName, typeof(string));
                    }
                }
                else
                {
                    dt.Rows.Add(tsv);
                }

            }


        }
    }
}

答案 1 :(得分:0)

我认为您需要在下面查询

public static Bitmap getBitmap(Context context, String url)
{
    final String CACHE_PATH = context.getCacheDir().getAbsolutePath() + "/picasso-cache/";

    File[] files=new File(CACHE_PATH).listFiles();
    for (File file:files)
    {
        String fname= file.getName();
        if (fname.contains(".") && fname.substring(fname.lastIndexOf(".")).equals(".0"))
        {
            try
            {
                BufferedReader br=new BufferedReader(new FileReader(file));
                if (br.readLine().equals(url))
                {
                    String image_path=  CACHE_PATH + fname.replace(".0", ".1");                     
                    if (new File(image_path).exists())
                    {
                        return BitmapFactory.decodeFile(image_path);
                    }
                }
            }
            catch (FileNotFoundException|IOException e)
            {
            }
        }
    }
    return null;
}

答案 2 :(得分:0)

我认为您的预期结果有误(1,periodId 5应该是35,不是吗?):

select a.UserID, p.PeriodId,
   datediff(minute,
   case when a.DateTimeFrom < p.DateTimeFrom 
        then p.DateTimeFrom else a.DateTimeFrom end,
   case when a.DateTimeTo > p.DateTimeTo 
        then p.DateTimeTo else a.DateTimeTo end) as minutes
from Activity a
inner join Periods p 
 on a.DateTimeTo > p.DateTimeFrom and 
    a.DateTimeFrom < p.DateTimeTo;

SQLFiddle sample

答案 3 :(得分:0)

您要为用户活动表中的每一行的日期时间范围与时段中的日期时间范围重叠的行将用户活动表联接到时段表中。另外,您希望结果集包括一列,该列具有计算出的重叠分钟数。

重叠分钟数可以用多种方式表示,但让我们将其表示为用户活动和时段开始时间最高者与用户活动和时段结束时间最低者之差。

然后我们可以写:

DECLARE @UserActivity table (UserId int, DatetimeFrom datetime, DatetimeTo datetime)

DECLARE @Period table (PeriodId int, DatetimeFrom datetime, DatetimeTo datetime)

INSERT INTO @UserActivity (UserId, DatetimeFrom, DatetimeTo)
    VALUES (1,'2018-01-01 10:00','2018-01-01 11:30'),
        (1,'2018-01-01 13:45','2018-01-01 14:20'),
        (2,'2018-01-01 10:50','2018-01-01 11:30'),
        (3,'2018-01-01 11:10','2018-01-01 12:00')

INSERT INTO @Period (periodId, DatetimeFrom, DatetimeTo)
    VALUES (1,'2018-01-01 09:30','2018-01-01 10:15'),  
    (2,'2018-01-01 10:15','2018-01-01 11:10'),
    (3,'2018-01-01 11:10','2018-01-01 12:00'),
    (4,'2018-01-01 12:00','2018-01-01 13:30'),
    (5,'2018-01-01 13:30','2018-01-01 15:00')

SELECT _UserActivity.UserId, _Period.PeriodId, _UserActivity.DatetimeFrom AS UserActivityDatetimeFrom, _UserActivity.DatetimeTo AS UserActivityDatetimeTo, _Period.DatetimeFrom AS PeriodDatetimeFrom, _Period.DatetimeTo AS PeriodDatetimeTo,
    DATEDIFF(minute, (SELECT MAX(x) FROM (VALUES (_UserActivity.DatetimeFrom), (_Period.DatetimeFrom)) AS VALUE(x)), (SELECT MIN(x) FROM (VALUES (_UserActivity.DatetimeTo), (_Period.DatetimeTo)) AS VALUE(x))) AS ActivityWithinPeriod
FROM @UserActivity AS _UserActivity
INNER JOIN @Period AS _Period ON (_Period.DatetimeFrom <= _UserActivity.DatetimeFrom AND _Period.DatetimeTo > _UserActivity.DatetimeFrom)
    OR  (_Period.DatetimeFrom < _UserActivity.DatetimeTo AND _Period.DatetimeTo > _UserActivity.DatetimeTo)
ORDER BY UserId, PeriodId

以上假设时间段日期时间是半开放时间间隔(即9:30 am到10:15 pm包括9.30am但不包括10:15 pm)。