我有一个关于我想写的SQL查询的问题。
我需要查询数据库中的数据。 该数据库包含以下3个字段:
Account_ID#,Date_Created,Time_Created
我需要编写一个查询,告诉我每小时打开多少个帐户。
我已经写过查询,但有时会创建0个帐户,因此结果中不会填充这些“小时”。
例如:
卷 日期 _ _Hour
435 12-Aug-12 03
213 12-Aug-12 04
125 12-Aug-12 06
如上例所示,小时5没有打开任何帐户。
有没有办法让结果可以填充小时,但是显示0个帐户在这个小时内打开? 我希望结果如何显示的示例:
交易量 日期 _Hour
435 12-Aug-12 03
213 12-Aug-12 04
0 12-Aug-12 05
125 12-Aug-12 06
谢谢!
更新:这是我目前所拥有的
SELECT count(*) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour
FROM accounts
WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-Aug-12','DD-Mon-RR')
GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24')
ORDER BY app_date, app_hour
答案 0 :(得分:2)
要获得所需的结果,您需要创建一个表(或使用查询生成“temp”表),然后使用左连接计算查询以获取每小时的行数 - 即使是那些0卷。
例如,假设我有一个包含app_date和app_hour字段的表。还假设此表格中包含您希望报告的每天/每小时的行。
查询将是:
SELECT NVL(c.num_apps,0) as num_apps, t.app_date, t.app_hour
FROM time_table t
LEFT OUTER JOIN
(
SELECT count(*) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour
FROM accounts
WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-Aug-12','DD-Mon-RR')
GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24')
ORDER BY app_date, app_hour
) c ON (t.app_date = c.app_date AND t.app_hour = c.app_hour)
答案 1 :(得分:1)
我认为最好的解决方案不是创建一些花哨的临时表,而只是使用这个结构:
select level
FROM Dual
CONNECT BY level <= 10
ORDER BY level;
这会给你(十行): 1 2 3 4 五 6 7 8 9 10
小时间隔只是很少修改:
select 0 as num_apps, (To_Date('16-09-12','DD-MM-RR') + level / 24) as created_ts
FROM dual
CONNECT BY level <= (sysdate - To_Date('16-09-12','DD-MM-RR')) * 24 ;
只是为了它为你添加解决方案的乐趣(我没有尝试语法,所以我很抱歉任何错误,但想法很清楚):
SELECT SUM(num_apps) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour
FROM(
SELECT count(*) as num_apps, created_ts
FROM accounts
WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-09-12','DD-MM-RR')
UNION ALL
select 0 as num_apps, (To_Date('16-09-12','DD-MM-RR') + level / 24) as created_ts
FROM dual
CONNECT BY level <= (sysdate - To_Date('16-09-12','DD-MM-RR')) * 24 ;
)
GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24')
ORDER BY app_date, app_hour
;
答案 2 :(得分:0)
您还可以在SELECT中使用CASE语句来强制所需的值。
答案 3 :(得分:0)
由于种种原因,有一个“序列表”可能会很有用,看起来像这样:
create table dbo.sequence
(
id int not null primary key clustered ,
)
加载数百万行,包括正值和负值。
然后,给出一个看起来像这样的表
create table dbo.SomeTable
(
account_id int not null primary key clustered ,
date_created date not null ,
time_created time not null ,
)
您的查询就像(在SQL Server中)一样简单:
select year_created = years.id ,
month_created = months.id ,
day_created = days.id ,
hour_created = hours.id ,
volume = t.volume
from ( select * ,
is_leap_year = case
when id % 400 = 0 then 1
when id % 100 = 0 then 0
when id % 4 = 0 then 1
else 0
end
from dbo.sequence
where id between 1980 and year(current_timestamp)
) years
cross join ( select *
from dbo.sequence
where id between 1 and 12
) months
left join ( select *
from dbo.sequence
where id between 1 and 31
) days on days.id <= case months.id
when 2 then 28 + years.is_leap_year
when 4 then 30
when 6 then 30
when 9 then 30
when 11 then 30
else 31
end
cross join ( select *
from dbo.sequence
where id between 0 and 23
) hours
left join ( select date_created ,
hour_created = datepart(hour,time_created ) ,
volume = count(*)
from dbo.SomeTable
group by date_created ,
datepart(hour,time_created)
) t on datepart( year , t.date_created ) = years.id
and datepart( month , t.date_created ) = months.id
and datepart( day , t.date_created ) = days.id
and t.hour_created = hours.id
order by 1,2,3,4
答案 4 :(得分:0)
我不清楚created_ts
是日期时间还是varchar。如果是日期时间,则不应使用to_date
;如果它是varchar,则不应使用to_char
。
假设它是一个日期时间,并借用@jakub.petr的FROM Dual CONNECT BY level
技巧,我建议:
SELECT count(*) as num_apps, to_char(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour
FROM (select level-1 as hour FROM Dual CONNECT BY level <= 24) h
LEFT JOIN accounts a on h.hour = to_number(to_char(a.created_ts,'HH24'))
WHERE created_ts >= To_Date('16-Aug-12','DD-Mon-RR')
GROUP BY trunc(created_ts), h.hour
ORDER BY app_date, app_hour