Получить все дни из пользовательского расписания - PullRequest
0 голосов
/ 03 мая 2018

У меня есть расписание пользователя, которое содержит его действия и время, потраченное на каждый день. Выглядит примерно так:

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 для дней, в которых нет журналов.

Есть ли способ сделать это с помощью одного запроса?

Ответы [ 4 ]

0 голосов
/ 03 мая 2018

Я не уверен, что понимаю задачу, но я поставил простое решение. Лучшая генерация календаря в 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
0 голосов
/ 03 мая 2018

РЕДАКТИРОВАТЬ: Если день имеет два раза ... и я предлагаю вам иметь уникальный / первичный идентификатор в вашей таблице.

Вы пытаетесь отобразить с помощью 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 ИЛИ, если я правильно понимаю ваш вопрос).

0 голосов
/ 03 мая 2018

Вам нужно написать таблицу календаря , затем LEFT JOIN таблицу календаря по таблице Original.

Вы можете использовать CTE recursive , чтобы написать календарь

  1. Пусть MIN(dt_log) будет fromDate, MAX(dt_log) будет Todate
  2. используйте 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

0 голосов
/ 03 мая 2018

Вы можете использовать это:

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 - это дата окончания в результате вывода.

Ссылка: Генерация дат между двумя диапазонами дат_AskTOM

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...