SQL COUNT特定日期的记录数

时间:2018-03-22 13:12:56

标签: sql sql-server count

我尝试创建一个SQL查询/存储过程来计算特定团队某一天正在进行的应用程序数量。

我遇到问题的方法如下:当应用程序转移给另一个用户时,当天的计数不应重复计算(转移当天每个团队的计数),并且应转到转移的用户

我的桌子

**Users**
Id  || Name   || TeamId
---------------------------------
 1     User 1     1
 2     User 2     2

**Application**
Id  || Name
------------- 
1      Application1

**ApplicationUser**
Id  || ApplicationId  || UserId || AssignedDate || UnassignedDate
----------------------------------------------------------
1           1               1        2018-03-01       2018-03-02
2           1               2        2018-03-02       2018-03-03

所以在存储过程中我发送一个日期作为参数,我想要返回的结果如下。

Date         || Team 1 || Team 2 || Total
-------------------------------------------
2018-03-02       0          1         1

所以,如果我将所有结果放在一起,它们就会像这样。

Date         || Team 1 || Team 2 || Total
-------------------------------------------
2018-02-28       0          0         0 
2018-03-01       1          0         1 
2018-03-02       0          1         1
2018-03-03       0          1         1

非常感谢你提前:)

4 个答案:

答案 0 :(得分:0)

试试这个:

DDL:

在这里,我定义表变量并插入您提供的数据:

declare @users table (id int, name varchar(10), teamid int)
insert into @users values (1, 'user1', 1),(2, 'user2',2)
declare @application table (id int, name varchar(15))
insert into @application values (1, 'application1')
declare @applicationuser table (id int, applicationid int, userid int, assigneddate date, unassigneddate date)
insert into @applicationuser values (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03')

查询:

--here I sum values for each team using cumulative sum
select [date],
       sum(team1) over (order by [date] rows between unbounded preceding and current row) [team1],
       sum(team2) over (order by [date] rows between unbounded preceding and current row) [team2],
       sum(total) over (order by [date] rows between unbounded preceding and current row) [total]
from (
    --here I am pivoting inner query, replacing NULL values using COALESCE
    select [date],
           coalesce(max(case when teamid = 1 then value end), 0) [team1],
           coalesce(max(case when teamid = 2 then value end), 0) [team2],
           coalesce(max(case when teamid = 1 then value end), 0) + coalesce(max(case when teamid = 2 then value end), 0) [total]
    from (
        --here I join assigned and unassigned dates with team ids
        select [AU].assigneddate [date], [U].teamid, 1 [value] from @applicationuser [AU] 
        join @users [U] on [AU].userid = [U].id

        union all

        select [AU].unassigneddate, [U].teamid, -1 from @applicationuser [AU] 
        join @users [U] on [AU].userid = [U].id
    ) a 
    group by [date]
) a

为了更好地理解这一点,分别尝试每个查询,即首先执行大多数内部查询,然后用外部查询包装并查看结果。通过这种方式,您可以了解每一步的情况。

答案 1 :(得分:0)

最好使用日期表处理这类查询。如果您的数据库中没有数据库,我强烈建议您购买一个。

同时,您可以使用内联表值函数或查询中的派生表动态创建日期表(注意我添加了一个额外的打开应用程序):

-- Declare test data
declare @users table (id int, name varchar(10), teamid int);
declare @application table (id int, name varchar(15));
declare @applicationuser table (id int, applicationid int, userid int, assigneddate date, unassigneddate date);

insert into @users values (1, 'user1', 1),(2, 'user2',2);
insert into @application values (1, 'application1'),(2, 'application1');
insert into @applicationuser values (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03'),(2,2,2,'2018-03-02','2018-03-05');


-- Find the maximum date range possible to create a dates table that covers all possible application periods
declare @MinDate date = (select min(AssignedDate) from @applicationuser);
declare @MaxDate date = (select max(UnassignedDate) from @applicationuser);

            -- This is a derived table that simply returns 10 rows
with t(t) as(select * from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(t))
            -- This then CROSS JOINs the 10 rows to create 10*10*10*10*10 = 100,000 rows
            -- Then uses the ROW_NUMBER function to add a number of days to the @MinDate value, to get a table of incrementing dates
    ,d(d) as(select top(datediff(day,@MinDate,@MaxDate)+1) dateadd(day,row_number() over (order by (select null))-1,@MinDate) from t,t t2,t t3,t t4,t t5)
select d.d                            -- Output is a row per date and teamid where there was an open application.
      ,u.teamid                       -- When grouped together this gives you a COUNT of open applications by teamid
      ,count(1) as OpenApplications
from d
    join @ApplicationUser as au
        on d.d between au.assigneddate and au.unassigneddate
    join @users as u
        on au.userid = u.id
group by d.d
      ,u.teamid
order by d.d
        ,u.teamid

输出:

+------------+--------+------------------+
|     d      | teamid | OpenApplications |
+------------+--------+------------------+
| 2018-03-01 |      1 |                1 |
| 2018-03-02 |      1 |                1 |
| 2018-03-02 |      2 |                2 |
| 2018-03-03 |      2 |                2 |
| 2018-03-04 |      2 |                1 |
| 2018-03-05 |      2 |                1 |
+------------+--------+------------------+

我故意不pivot编辑您的数据以匹配您想要的输出,因为这几乎总是一个坏主意。随着您的团队数量的变化,您输出的列数和名称将发生变化,这将需要不断维护。相反,您应该只输出一组正常数据,并在最终到达表示层后将pivot留给表示层。

答案 2 :(得分:0)

这个用法是否完整:

    DECLARE @users TABLE (id INT, name VARCHAR(10), teamid INT)
    INSERT INTO @users VALUES (1, 'user1', 1),(2, 'user2',2)
    DECLARE @application TABLE (id INT, name VARCHAR(15))
    INSERT INTO @application VALUES (1, 'application1')
    DECLARE @applicationuser TABLE (id INT, applicationid INT, userid INT, assigneddate DATE, unassigneddate DATE)
    INSERT INTO @applicationuser VALUES (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03')


    DECLARE @assignment TABLE([date] DATE,teamid INT,[value] INT)

    INSERT INTO @assignment
    SELECT [AU].assigneddate [date], [U].teamid, 1 [value]
    FROM @applicationuser [AU] 
    JOIN @users [U] ON [AU].userid = [U].id

    INSERT INTO @assignment
    SELECT [AU].unassigneddate, [U].teamid, 
        CASE WHEN  LEAD(AssignedDate) OVER(ORDER BY [AU].id)=unassigneddate 
            THEN -1
        ELSE 
            1
        END         
    FROM @applicationuser [AU] 
    JOIN @users [U] ON [AU].userid = [U].id


    SELECT b.[date],
        CASE WHEN t1.teamid=1 
            THEN 1 
        ELSE 
            0 
        END AS Team1,
        CASE WHEN t1.teamid=2 
            THEN 1 
        ELSE 
            0 
        END AS Team2,
        total
    FROM
    (
        SELECT [date],  MAX([value]) AS Total
        FROM @assignment
        group by [date]
    )b
    INNER JOIN @assignment t1 ON b.Total=t1.Value AND b.[date]=t1.[date]
    ORDER BY b.[date]

答案 3 :(得分:0)

非常感谢您的所有答案。

我自己也在尝试这个,我似乎找到了问题的答案。

DECLARE @DATE DATETIME 
SELECT @DATE = '20180301'

SELECT ApplicationId, Max(UnassignedDate) as UnassignedDate
INTO #TempApplicationUsers 
FROM ApplicationUsers
WHERE @DATE > DAteAdd(Day, -1, AssignedDate) and (@DATE < UnassignedDate OR 
UnassignedDate is NULL)
Group BY ApplicationId

SELECT * From  #TempApplicationUsers

SELECT UserId, COUNT(*) FROM ApplicationUsers, #TempApplicationUsers 
WHERE ApplicationUsers.ApplicationId = #TempApplicationUsers.ApplicationId 
and ISNULL(ApplicationUsers.UnassignedDate, 0) = 
ISNULL(#TempApplicationUsers.UnassignedDate, 0)
GROUP BY UserId
DROP TABLE #TempApplicationUsers

这将返回当天每个用户的计数,从中我可以通过users表中的TeamId得到每个团队的计数。

再次感谢您

相关问题