我有一个用户日程表,其中包含他的活动和每天所花费的时间。 看起来像这样:
cd_user | dt_log | time_spent
123 | 01/01/2018 | 60
123 | 01/01/2018 | 35
123 | 02/01/2018 | 55
123 | 05/01/2018 | 45
我想得到每天花费的所有时间的总和,但我需要在没有任何日志的日子里返回0。
有没有办法用一个查询来做到这一点?
答案 0 :(得分:1)
你可以用这个:
WITH table_name AS
(
SELECT 123 AS cd_user, TO_DATE('01/01/2018','dd/mm/yyyy') AS dt_log, 60 AS time_spent
FROM dual UNION ALL
SELECT 123, TO_DATE('01/01/2018','dd/mm/yyyy'), 35 FROM dual UNION ALL
SELECT 123, TO_DATE('02/01/2018','dd/mm/yyyy'), 55 FROM dual UNION ALL
SELECT 123, TO_DATE('05/01/2018','dd/mm/yyyy'), 45 FROM dual
)
, date_range AS
(
SELECT TO_DATE('01/01/2018','dd/mm/yyyy') + ROWNUM - 1 AS date1
FROM all_objects
WHERE ROWNUM <= TO_DATE('11/01/2018','dd/mm/yyyy') - TO_DATE('01/01/2018','dd/mm/yyyy') + 1
)
SELECT u.cd_user,
d.date1 AS dt_log,
SUM(NVL(t.time_spent, 0)) AS total_time_spent
FROM date_range d
CROSS JOIN (SELECT DISTINCT cd_user FROM table_name) u
LEFT JOIN table_name t
ON d.date1 = TRUNC(t.dt_log) AND u.cd_user = t.cd_user
GROUP BY u.cd_user, d.date1
ORDER BY u.cd_user, d.date1;
如果dt_log
没有时间参与其中,您可以省略TRUNC
。
在此示例中,01/01/2018
是开始日期,11/01/2018
是输出结果中的结束日期。
答案 1 :(得分:0)
您需要按原始表格编写日历表,然后编写LEFT JOIN
日历表。
您可以使用 CTE recursive 来编写日历
MIN(dt_log)
来自日期,MAX(dt_log)
为Todate CTE
制作WITH CTE(from_date, i, datediff,cd_user) AS
(
SELECT MIN(dt_log) from_date, 1 AS i, trunc(MAX(dt_log) - MIN(dt_log)) as datediff,cd_user
FROM t
GROUP BY cd_user
UNION ALL
SELECT from_date, i + 1, datediff,cd_user
FROM CTE
WHERE i <= datediff
), dates as (select i, from_date + i - 1 Dt,cd_user from CTE)
SELECT d.CD_USER,d.DT,SUM(coalesce(t.TIME_SPENT,0)) cost
FROM dates d
LEFT JOIN T t on t.CD_USER = d.CD_USER
AND d.Dt = t.dt_log
group by d.CD_USER,d.DT
ORDER BY d.CD_USER,d.DT
sqlfiddle:http://sqlfiddle.com/#!4/a461d/4
您还可以使用connect by
撰写日历
WITH CTE as (
SELECT cd_user,MIN(dt_log) FromDate,MAX(dt_log) ToDate
FROM T
GROUP BY cd_user
), calendar as
(
select DISTINCT cd_user,(FromDate+level-1) dt
from CTE
connect by level <=ToDate - FromDate + 1
)
select d.CD_USER,d.DT,SUM(coalesce(t.TIME_SPENT,0)) cost
from calendar d
LEFT JOIN T t on t.CD_USER = d.CD_USER
AND d.dt = t.dt_log
group by d.CD_USER,d.DT
ORDER BY d.CD_USER,d.DT
sqlfiddle:http://sqlfiddle.com/#!4/a461d/9
答案 2 :(得分:0)
我不确定我是否理解这项任务,但我提出了一个简单的解决方案。在https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:14582643282111
中生成更好的日历 --drop table test_tab
create table test_tab(
cd_user number,
dt_log date,
time_spent number
)
;
insert into test_tab values(123 , to_date('01/01/2018', 'DD/MM/YYYY') , 60);
insert into test_tab values(123 , to_date('01/01/2018', 'DD/MM/YYYY') , 35);
insert into test_tab values(123 , to_date('02/01/2018', 'DD/MM/YYYY') , 55);
insert into test_tab values(123 , to_date('05/01/2018', 'DD/MM/YYYY') , 45);
insert into test_tab values(999 , to_date('05/01/2018', 'DD/MM/YYYY') , 45);
commit;
with calendar as(
SELECT to_date('01/01/2018', 'DD/MM/YYYY')+level-1 as dt
FROM dual connect by level < 10 --days
)
SELECT cd_user, nvl(dt_log, dt), nvl(sum(time_spent),0)
FROM test_tab, calendar
where dt_log(+) = dt
group by cd_user, nvl(dt_log, dt)
order by 2;
-- sample 2 with not null cd_user for emty entrence
with calendar as(
SELECT to_date('01/01/2018', 'DD/MM/YYYY')+level-1 as dt
FROM dual connect by level < 10 --days
),users1 as(
SELECT distinct CD_USER FROM test_tab
), cal_users as(
select cd_user, dt
from calendar, users1
)
select cu.CD_USER, cu.dt, nvl(sum(c.time_spent),0)
from cal_users cu, test_tab c
where cu.cd_user = c.cd_user(+)
and cu.dt = c.dt_log(+)
group by cu.CD_USER, cu.dt
order by 1,2
答案 3 :(得分:-1)
编辑:如果这一天有两次......我建议您在表格中有一个唯一/主要ID。
你想用php显示吗?如果是......
我不知道单个查询,但是......
$curr_date = '';
$time_spent = 0;
// months
for($i = 1; $i <= 12; $i++) {
// add a leading zero to months less than October
if($i > 10) { $curr_date .= '0'; }
$curr_date .= $i.'/';
// number of days for each month
if($i == 2) { $days = 28; }
else if($i == 4 || $i == 6 || $i == 9 || $i == 11) { $days = 30; }
else { $days = 31; }
// days
for($j = 1; $j <= $days; $j++) {
// add a leading zero to days less than 10
if($j > 10) { $curr_date .= '0'; }
$curr_date .= $j.'/2018';
// search for table if that date is there for the user
// replace 123 with a variable if you have more than one user
$SQL = "SELECT * FROM table_name WHERE cd_user = 123 AND dt_log = '$curr_date'";
$result = mysqli_query($connect, $SQL);
$num = mysqli_num_rows($result);
// if that date is in the table
if($num != 0) {
while($field = mysqli_fetch_assoc($result)) {
$time_spent += $field['time_spent'];
}
echo $curr_date.' time spent: '.$time_spent;
// set time spent back to zero for next day
$time_spent = 0;
}
// if that date is not in the table
else { echo $curr_date.' time spent: '.$time_spent; }
}
}
所以你去吧。对不起,这是一个带有某些代码的单一查询语句,但它可以做你想要的...我想(如果你试图用php显示它或者如果我正确理解你的问题)。