简体   繁体   English

SQL查询以计算每天每个状态中的对象数

[英]SQL query to count number of objects in each state on each day

Given a set of database records that record the date when an object enters a particular state, I would like to produce a query that shows how many objects are in each state on any particular date.给定一组记录对象进入特定状态的日期的数据库记录,我想生成一个查询,显示在任何特定日期每个状态有多少对象。 The results will be used to produce trend reports showing how the number of objects in each state changes over time.结果将用于生成趋势报告,显示每个状态中的对象数量如何随时间变化。

I have a table like the following that records the date when an object enters a particular state:我有一个如下表,记录对象进入特定状态的日期:

ObjID EntryDate  State
----- ---------- -----
    1 2014-11-01   A
    1 2014-11-04   B
    1 2014-11-06   C
    2 2014-11-01   A
    2 2014-11-03   B
    2 2014-11-10   C
    3 2014-11-03   B
    3 2014-11-08   C

There are an arbitrary number of objects and states.有任意数量的对象和状态。

I need to produce a query that returns the number of objects in each state on each date.我需要生成一个查询,返回每个日期每个状态中的对象数。 The result would look like the following:结果如下所示:

Date       State Count
---------- ----- -----
2014-11-01   A       2
2014-11-01   B       0
2014-11-01   C       0
2014-11-02   A       2
2014-11-02   B       0
2014-11-02   C       0
2014-11-03   A       1
2014-11-03   B       2
2014-11-03   C       0
2014-11-04   A       0
2014-11-04   B       3
2014-11-04   C       0
2014-11-05   A       0
2014-11-05   B       3
2014-11-05   C       0
2014-11-06   A       0
2014-11-06   B       2
2014-11-06   C       1
2014-11-07   A       0
2014-11-07   B       2
2014-11-07   C       1
2014-11-08   A       0
2014-11-08   B       1
2014-11-08   C       2
2014-11-09   A       0
2014-11-09   B       1
2014-11-09   C       2
2014-11-10   A       0
2014-11-10   B       0
2014-11-10   C       3

I'm working with an Oracle database.我正在使用 Oracle 数据库。

I haven't been able to find an example that matches my case.我一直无法找到与我的情况相匹配的示例。 The following questions look like they are asking for solutions to similar but different problems:以下问题看起来像是在寻求类似但不同问题的解决方案:

Any help or hints that can be provided would be much appreciated.任何可以提供的帮助或提示将不胜感激。

SELECT EntryDate AS "Date", State, COUNT(DISTINCT ObjectId) AS "Count" GROUP BY EntryDate, State ORDER BY EntryDate, State;

As each state is not recorded every date , you need to do CROSS JOIN to get the unique states and then do GROUP BY .由于不是每个日期都记录每个状态,因此您需要执行 CROSS JOIN 以获取唯一状态,然后执行GROUP BY

SELECT EntryDate, 
       C.State, 
       SUM(case when C.state = Table1.state then 1 else 0 end) as Count
FROM Table1
CROSS JOIN ( SELECT DISTINCT State FROM Table1) C
GROUP BY EntryDate, C.State
ORDER BY EntryDate

I'm going to do a quick and dirty way to get numbers.我将采取一种快速而肮脏的方式来获取数字。 You can choose your preferred method .您可以选择您喜欢的方法。 . . . . using recursive CTEs, connect by , or a numbers table.使用递归 CTE、 connect by或数字表。 So, the following generates the all combinations of the dates and states.因此,以下生成日期和状态的所有组合。 It then uses a correlated subquery to count the number of objects in each state on each date:然后它使用相关子查询来计算每个日期每个状态中的对象数量:

with n as (
      select rownum - 1 as n
      from table t
     ),
     dates as (
      select mind + n.n
      from (select min(date) as mind, max(date) as maxd from table) t
      where mind + n.n <= maxd
     )
select d.date, s.state,
       (select count(*)
        from (select t2.*, lead(date) over (partition by ObjId order by date) as nextdate
              from table t2
             ) t2
        where d.date >= t2.date and (d.date < t2.nextdate or t2.nextdate is null) and
              d.state = t2.state
       ) as counts
from dates d cross join
     (select distinct state from table t)

This query will list how many objects ENTERED a particular state on each day, assuming each object only changes state ONCE a day.此查询将列出每天有多少对象进入特定状态,假设每个对象每天仅更改一次状态。 If objects change state more than once a day, you would need to use count(distinct objid):如果对象每天改变状态不止一次,你需要使用 count(distinct objid):

select entrydate, state, count(objid) 
from my_table
group by entrydate, state
order by entrydate, state

However, you are asking how many objects ARE in a particular state on each day, thus you would need a very different query to show that.但是,您要询问每天有多少对象处于特定状态,因此您需要一个非常不同的查询来显示这一点。 Since you only provide that particular table in your example, I'll work with that table only:由于您仅在示例中提供该特定表,因此我将仅使用该表:

select alldatestates.entrydate, alldatestates.state, count(statesbyday.objid)
from
    (
    select alldates.entrydate, allstates.state
    from (select distinct entrydate from mytable) alldates,
         (select distinct state from mytable) allstates
    ) alldatestates
    left join
    (
    select alldates.entrydate, allobjs.objid, (select min(state) as state from mytable t1 
                                          where t1.objid = allobjs.objid and 
                                                t1.entrydate = (select max(entrydate) from mytable t2 
                                                                where t2.objid = t1.objid and
                                                                      t2.entrydate <= alldates.entrydate)) as state
    from (select distinct entrydate from mytable) alldates,
         (select distinct objid from mytable) allobjs
    ) statesbyday
    on alldatestates.entrydate = statesbyday.entrydate and alldatestates.state = statesbyday.state
group by alldatestates.entrydate, alldatestates.state
order by alldatestates.entrydate, alldatestates.state

Of course, this query will be much simpler if you have a table for all the possible states and another one for all the possible object ids.当然,如果您有一个包含所有可能状态的表和一个包含所有可能对象 ID 的表,则此查询会简单得多。

Also, probably you could find a query simpler than that, but this one works.此外,您可能会发现一个比这更简单的查询,但这个有效。 The downside is, it could very quickly become an optimizer's nightmare!缺点是,它很快就会成为优化器的噩梦! :) :)

Try this query :试试这个查询:

select EntryDate As Date, State, COUNT(ObjID) AS Count from table_name
GROUP BY EntryDate , State 
ORDER BY State

You can try this with analytic function as well:您也可以使用分析功能尝试此操作:

Select
Date,
State,
count(distinct obj) OVER (PARTITION BY EntryDate, State) count
from table
order by 1;

选择 EntryDate 作为 Date、State、Count(Distinct ObjID) 作为 Count From Table_1 按 EntryDate、State 分组

Working out of SQL SERVER because I'm more familiar, but here's what I've got so far:使用 SQL SERVER 因为我更熟悉,但这是我到目前为止所得到的:

fiddle example (SQL SERVER but the only difference should be the date functions I think...): http://sqlfiddle.com/#!3/8b9748/2小提琴示例(SQL SERVER,但唯一的区别应该是我认为的日期函数......): http ://sqlfiddle.com/#!3/8b9748/2

WITH zeroThruNine AS (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9), 
nums AS (SELECT 10*b.n+a.n AS n FROM zeroThruNine a, zeroThruNine b), 
Dates AS (
    SELECT DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t)) AS Date
    FROM nums n
    WHERE DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t))<=(SELECT MAX(t.EntryDate) FROM @tbl t)
), Data AS (
    SELECT d.Date, t.ObjID, t.State, ROW_NUMBER() OVER (PARTITION BY t.ObjID, d.Date ORDER BY t.EntryDate DESC) as r
    FROM Dates d, @tbl t
    WHERE d.Date>=t.EntryDate
)
SELECT t.Date, t.State, COUNT(*)
FROM Data t
WHERE t.r=1
GROUP BY t.Date, t.State
ORDER BY t.Date, t.State

First, start off making a numbers table (see http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html ) for examples.首先,开始制作一个数字表(参见http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary- numbers-table.html ) 示例。 There are different ways to create number tables in different databases, so the first two WITH expressions I've created are just to create a view of the numbers 0 through 99. I'm sure there are other ways, and you may need more than just 100 numbers (representing 100 dates between the first and last dates you provided)在不同的数据库中创建数字表有不同的方法,所以我创建的前两个 WITH 表达式只是创建数字 0 到 99 的视图。我相信还有其他方法,你可能需要更多只有 100 个数字(代表您提供的第一个和最后一个日期之间的 100 个日期)

So, once you get to the Dates CTE, the main part is the Data CTE因此,一旦您到达 Dates CTE,主要部分就是 Data CTE

It finds each date from the Dates cte, and pairs it with the values of the @tbl table (your table) with any States that were recorded after said date.它从 Dates cte 中找到每个日期,并将其与 @tbl 表(您的表)的值与在所述日期之后记录的任何状态配对。 It also marks the order of which states/per objid in decreasing order.它还以降序标记了哪些状态/每个 objid 的顺序。 That way, in the final query, we can just use WHERE tr=1 to get the max state for each objid per date这样,在最终查询中,我们可以只使用 WHERE tr=1 来获取每个 objid 每个日期的最大状态

One issue, this gets data for all dates, even those where nothing was recorded, but for zero-counts, it doesn't return anything.一个问题,这会获取所有日期的数据,即使是那些没有记录任何内容的日期,但对于零计数,它不会返回任何内容。 If you wanted to, you could left join this result with a view of distinct states and take 0 when no join was made如果你愿意,你可以离开加入这个结果并查看不同的状态,并在没有加入时取 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM