[英]SQL query to count number of objects in each state on each day
给定一组记录对象进入特定状态的日期的数据库记录,我想生成一个查询,显示在任何特定日期每个状态有多少对象。 结果将用于生成趋势报告,显示每个状态中的对象数量如何随时间变化。
我有一个如下表,记录对象进入特定状态的日期:
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
有任意数量的对象和状态。
我需要生成一个查询,返回每个日期每个状态中的对象数。 结果如下所示:
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
我正在使用 Oracle 数据库。
我一直无法找到与我的情况相匹配的示例。 以下问题看起来像是在寻求类似但不同问题的解决方案:
任何可以提供的帮助或提示将不胜感激。
SELECT EntryDate AS "Date", State, COUNT(DISTINCT ObjectId) AS "Count" GROUP BY EntryDate, State ORDER BY EntryDate, State;
由于不是每个日期都记录每个状态,因此您需要执行 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
我将采取一种快速而肮脏的方式来获取数字。 您可以选择您喜欢的方法。 . . 使用递归 CTE、 connect by
或数字表。 因此,以下生成日期和状态的所有组合。 然后它使用相关子查询来计算每个日期每个状态中的对象数量:
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)
此查询将列出每天有多少对象进入特定状态,假设每个对象每天仅更改一次状态。 如果对象每天改变状态不止一次,你需要使用 count(distinct objid):
select entrydate, state, count(objid)
from my_table
group by entrydate, state
order by entrydate, state
但是,您要询问每天有多少对象处于特定状态,因此您需要一个非常不同的查询来显示这一点。 由于您仅在示例中提供该特定表,因此我将仅使用该表:
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
当然,如果您有一个包含所有可能状态的表和一个包含所有可能对象 ID 的表,则此查询会简单得多。
此外,您可能会发现一个比这更简单的查询,但这个有效。 缺点是,它很快就会成为优化器的噩梦! :)
试试这个查询:
select EntryDate As Date, State, COUNT(ObjID) AS Count from table_name
GROUP BY EntryDate , State
ORDER BY State
您也可以使用分析功能尝试此操作:
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 分组
使用 SQL SERVER 因为我更熟悉,但这是我到目前为止所得到的:
小提琴示例(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
首先,开始制作一个数字表(参见http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary- numbers-table.html ) 示例。 在不同的数据库中创建数字表有不同的方法,所以我创建的前两个 WITH 表达式只是创建数字 0 到 99 的视图。我相信还有其他方法,你可能需要更多只有 100 个数字(代表您提供的第一个和最后一个日期之间的 100 个日期)
因此,一旦您到达 Dates CTE,主要部分就是 Data CTE
它从 Dates cte 中找到每个日期,并将其与 @tbl 表(您的表)的值与在所述日期之后记录的任何状态配对。 它还以降序标记了哪些状态/每个 objid 的顺序。 这样,在最终查询中,我们可以只使用 WHERE tr=1 来获取每个 objid 每个日期的最大状态
一个问题,这会获取所有日期的数据,即使是那些没有记录任何内容的日期,但对于零计数,它不会返回任何内容。 如果你愿意,你可以离开加入这个结果并查看不同的状态,并在没有加入时取 0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.