SQL Examples

A collection of SQL commands to quick start your statistic query

This page contains collections of SQL statements, which were helpful in the past and might be of use for other people as well.

Summary of total duration, grouped by customer and user

SELECT
    c.name as Customer,
    u.username as Username,
    u.alias as User,
    FORMAT(SUM(t.duration) / 3600, 0) as Duration
FROM
    kimai2_timesheet t
        LEFT JOIN kimai2_projects p on t.project_id = p.id
        LEFT JOIN kimai2_customers c on p.customer_id = c.id
        LEFT JOIN kimai2_users u on t.user = u.id
GROUP BY
    c.id, t.user, c.name, u.username, u.alias
;

The output looks like this:

Customer Username User Duration
Acme company test@example.com John Doe 1,745.4
Acme company chris_user Chris Maier 45.8
Foo Bar test@example.com John Doe 345.0

Duration is formatted as decimal time. So 1,745.4 is one-thousand-seven-hundred-forty-five hours and 24 minutes.

Summary of total duration, grouped by user and customer

SELECT
    u.username as Username,
    u.alias as User,
    c.name as Customer,
    FORMAT(SUM(t.duration) / 3600, 0) as Duration
FROM
    kimai2_timesheet t
    LEFT JOIN kimai2_projects p on t.project_id = p.id
    LEFT JOIN kimai2_customers c on p.customer_id = c.id
    LEFT JOIN kimai2_users u on t.user = u.id
GROUP BY
    t.user, u.username, u.alias, c.id, c.name
;
Username User Customer Duration
test@example.com John Doe Acme company 1,745.4
test@example.com John Doe Foo Bar 345.0
chris_user Chris Maier Acme company 45.8

Duration is formatted as decimal time. So 1,745.4 is one-thousand-seven-hundred-forty-five hours and 24 minutes.

Find entries where hourly rate does not match users’ hourly rate

It compares timesheet hourly rate and user-preference rate. It does not check configured customer/project/activity rates!

SELECT
    t.id, t.user as "User ID", u.username,
    t.duration as Duration,
    t.hourly_rate as "Timesheet rate",
    COALESCE(p.value, 0.00) as "Configured rate",
    t.rate as "Current rate",
    round((COALESCE(p.value, 0.00) * (t.duration / 3600)), 2) as "Possible rate"
FROM
    kimai2_timesheet t
LEFT JOIN
    kimai2_users u ON t.user = u.id
LEFT JOIN
    kimai2_user_preferences p on u.id = p.user_id
WHERE
    p.name = 'hourly_rate'
    and t.hourly_rate != COALESCE(p.value, 0.00)
order by rate DESC;

Find users without explicit hourly rate

SELECT u.id, u.username, COALESCE(p.value, 0.00) as hourly_rate
FROM kimai2_users u LEFT JOIN kimai2_user_preferences p on u.id = p.user_id
WHERE p.name = 'hourly_rate'
AND COALESCE(p.value, 0.00) = 0.00;

Update timesheet rates by user configuration

These statements are only meant as idea! Update timesheet rates by configured users rates. Does not use configured customer/project/activity rates.

UPDATE kimai2_timesheet t
RIGHT JOIN kimai2_users u ON t.user = u.id
RIGHT JOIN kimai2_user_preferences p on u.id = p.user_id
SET
    t.hourly_rate = COALESCE(p.value, 0),
    t.rate = round((COALESCE(p.value, 0) * (COALESCE(t.duration,0) / 3600)), 2)
WHERE p.name = 'hourly_rate';

UPDATE kimai2_timesheet t
RIGHT JOIN kimai2_users u ON t.user = u.id
RIGHT JOIN kimai2_user_preferences p on u.id = p.user_id
SET t.internal_rate = round((COALESCE(p.value, 0) * (COALESCE(t.duration,0) / 3600)), 2)
WHERE p.name = 'internal_rate';

Find all configured projects rates

In case you want to see a list of all configured project rates at a glance:

SELECT c.name          AS Kunde,
       p.name          AS Projekt,
       r.rate          AS Stundensatz,
       r.internal_rate AS "Interner Satz",
       k2u.username    AS Benutzer
FROM kimai2_projects p
         LEFT JOIN kimai2_customers c ON p.customer_id = c.id
         LEFT JOIN kimai2_projects_rates r ON p.id = r.project_id
         LEFT JOIN kimai2_users k2u ON r.user_id = k2u.id
Top