SQL Query to return Month days as Columns and Total Hours as Row - sql

i am working on an Attendance report were I need to create a SQL Query from one table to return the attendance of employees net hours worked over the month.
Day of the month should be as a column and in the rows should be the total Hours of employee.
The Table is having 6 Columns ( Employee Name, Dept , Position, Time In , Time Out and Total Hours
Picture for Selecting * From the Attendance Table
i want to return the values as the following:
EmployeeName | 1st | 2nd | 3rd | 4th | ...... |30 June
Emp 1 | 10:30 | | 10:40 | | 10:10 | | 10:21 |
The Days column should be returned in a parameter so i can add it to crystal report.
Table Structure
if you can advise please.
Thanks in advance

You can use CASE statment like this:
SELECT EmployeeName,
(CASE WHEN EXTRACT(YEAR FROM DATE) = 2017 AND EXTRACT(MONTH FROM DATE) = 6 AND EXTRACT(DAY FROM DATE) = 1 then totalHours ELSE NULL END) AS "01/06",
(CASE WHEN EXTRACT(YEAR FROM DATE) = 2017 AND EXTRACT(MONTH FROM DATE) = 6 AND EXTRACT(DAY FROM DATE) = 2 then totalHours ELSE NULL END) AS "02/06",
.
.
.
(CASE WHEN EXTRACT(YEAR FROM DATE) = 2017 AND EXTRACT(MONTH FROM DATE) = 6 AND EXTRACT(DAY FROM DATE) = 30 then totalHours ELSE NULL END) AS "30/06"
FROM Attendance
So, for each day a new column will be created.

I used something like this
CREATE TABLE `AxsLog` (
`id` integer NOT NULL UNIQUE,
`Logon` text NOT NULL DEFAULT current_timestamp,
`Logoff` text NOT NULL DEFAULT current_timestamp,
`Duration` text NOT NULL DEFAULT 0,
`SysDat` text NOT NULL DEFAULT current_timestamp,
PRIMARY KEY(`id`) );
You can easily add an FK column for each row in your user table.
Keep the logon id for each entry, then update that line on logoff
UPDATE AxsLog
Set Duration= (SELECT sum( strftime('%s', logoff) - strftime('%s', logon) )
/60 FROM AxsLog WHERE id= 1 )
WHERE id= 1 ;
To build a report, use something like this. This query only gives a total per month.
select total(Duration)
FROM AxsLog where substr(sysdat,6,2) = 'month'

your requirement can be fulfill by using crosstab report or if u want to achieve in sql then use pivot

Related

SQL query: get total values for each month

I have a table that stores, number of fruits sold on each day. Stores number of items sold on particular date.
CREATE TABLE data
(
code VARCHAR2(50) NOT NULL,
amount NUMBER(5) NOT NULL,
DATE VARCHAR2(50) NOT NULL,
);
Sample data
code |amount| date
------+------+------------
aple | 1 | 01/01/2010
aple | 2 | 02/02/2010
orange| 3 | 03/03/2010
orange| 4 | 04/04/2010
I need to write a query, to list out, how many apple and orange sold for jan and february?
--total apple for jan
select sum(amount) from mg.drum d where date >='01/01/2010' and cdate < '01/02/2020' and code = 'aple';
--total apple for feb
select sum(amount) from mg.drum d where date >='01/02/2010' and cdate < '01/03/2020' and code = 'aple';
--total orange for jan
select sum(amount) from mg.drum d where date >='01/01/2010' and cdate < '01/02/2020' and code = 'orange';
--total orange for feb
select sum(amount) from mg.drum d where date >='01/02/2010' and cdate < '01/03/2020' and code = 'orange';
If I need to calculate for more months, more fruits, its tedious.is there a short query to write?
Can I combine at least for the months into 1 query? So 1 query to get total for each month for 1 fruit?
You can use conditional aggregation such as
SELECT TO_CHAR("date",'MM/YYYY') AS "Month/Year",
SUM( CASE WHEN code = 'apple' THEN amount END ) AS apple_sold,
SUM( CASE WHEN code = 'orange' THEN amount END ) AS orange_sold
FROM data
WHERE "date" BETWEEN date'2020-01-01' AND date'2020-02-29'
GROUP BY TO_CHAR("date",'MM/YYYY')
where date is a reserved keyword, cannot be a column name unless quoted.
Demo
select sum(amount), //date.month
from mg.drum
group by //date.month
//data.month Here you can give experssion which will return month number or name.
If you are dealing with months, then you should include the year as well. I would recommend:
SELECT TRUNC(date, 'MON') as yyyymm, code,
SUM(amount)
FROM t
GROUP BY TRUNC(date, 'MON'), code;
You can add a WHERE clause if you want only some dates or codes.
This will return a separate row for each row that has data. That is pretty close to the results from your four queries -- but this does not return 0 values.
select to_char(date_col,'MONTH') as month, code, sum(amount)
from mg.drum
group by to_char(date_col,'MONTH'), code

how to fetch count data of 2 date fields in same month in SQL

I am trying to create a query where I have 3 column.
C_Time: contains task Creation date time
Done_Time: Contains Task completion date time
User ID: Unique id of user
I want to get result where I want to get total count of created tasks in particular month and total number of done task at that same month grouped by user id
Output will be like:
UserID | CreatedCount | DoneCount
------------------------------------------
U12 | 12 | 12
-------------------------------------------
U13 | 7 | 5
here U12 user have created 12 tasks and completed 12 tasks in January 2020 month. But user U13 created 7 tasks in Jan 2020 and done 5 tasks in same month.
You can use apply to unpivot the data and then aggregation:
select t.user_id, sum(is_create), sum(is_complete)
from t cross apply
(values (t.c_time, 1, 0), (t.done_time, 0, 1)
) v(t, is_create, is_complete)
where v.t >= '2020-01-01' and v.t < '2020-02-01'
group by t.user_id;
You can also do this with conditional aggregation:
select user_id,
sum(case when c_time >= '2020-01-01' and c_time < '2020-02-01' then 1 else 0 end),
sum(case when done_time >= '2020-01-01' and done_time < '2020-02-01' then 1 else 0 end)
from t
group by user_id;
This is probably a little faster for your particular example. However, the first version is more generalizable -- for instance, it allows you to summarize easily by both user and month.

Select users based on their date joined and date left

I have the following table:
Person
UserID Name Date_Joined Date_Left
1 Test 2018-08-10 NULL
2 Test2 2018-07-10 NULL
3 Test3 2018-07-10 2018-12-31
4 Test4 2018-08-10 2018-09-10
I want to check by only their join and/or left date if they are billable(=active) or not.
These are billable users:
User whose start month is at least one month before billdate
with no date left
User whose start month is at least one month before billdate
with date left month equal to the billdate or later than the
billdate
Month of billing = always the previous month.
I use the following query:
DECLARE #billdate AS DATE = '2018-09-01';
SELECT *
FROM person
WHERE CompanyID = 1205 AND (
(
date_joined <= EOMONTH(#billdate, -1)
)
OR
(
date_left > EOMONTH(#billdate, -1) AND
date_left <= EOMONTH(#billdate)
)
)
My problems:
User Test4 is still present in my table if I set the billdate to 2018-11-01.
User Test3 dissapears if i set billdate to 2019-01-01
What is wrong with my query and how can I optimize this?
Sample data:
User list:
1 - Test - 2018-08-10 - NULL
2 - Test2 - 2018-07-10 - NULL
3 - Test3 - 2018-07-10 - 2018-12-31
4 - Test4 - 2018-08-10 - 2018-09-10
For the bill period of the previous month (= 8 / August) = #billdate 2018-09-10, these are the billable users:
Test2
Test3
However, when I change the bill period to 10 / october, these are the billable users:
Test
Test2
Test3
If I understand your logic correctly, a billable user is one whose start month is at least one month before the current month, and whose end month is less than or equal to the current month.
SELECT *,
CASE WHEN #billdate >= DATEADD(d, 1, EOMONTH(date_joined)) AND
(#billdate <= DATEADD(d, 1, EOMONTH(date_left)) OR date_left IS NULL)
THEN 'billable'
ELSE 'not billable' END AS status
FROM person;
This billing logic appears to be consistent with customers getting the first month free, but being billable from the second up to the final month.
Demo
use make flag comparing join month and year with bill month and year and create a flag for each user then use sub-query for filter
select * from t
(
select *,case when (month(date_joined)=month(billdate)
and year(date_joined)=year(billdate)) then 'N' else 'Y' end as flag_billable
from user
) as t where t.flag_billable='Y'
For your query
DECLARE #billdate AS DATE = '2018-09-01';
select * from
(
SELECT * ,case when (month(date_joined)=month(#billdate)
and year(date_joined)=year(#billdate)) then 'N' else 'Y' end as flag_billable
FROM person
) t where t.flag_billable='Y'

Query to output data from multiple days

I have this query:
select count(distinct orderid), employeeinfo.Name
from orderinfo, employeeinfo
where preparedate = '2014-11-10'
and prepareby = employeeid
group by employeeinfo.name
It outputs data like
1 | Jeff
4 | Bob
5 | Steve
Is there a way to make this work for a date range so that I can graph the data in excel?
if I want to line graph data for every day for the month of December
I'm not sure, what's your expected output, but to get a date range, you could use:
select count(distinct orderid), employeeinfo.Name
from orderinfo, employeeinfo
where preparedate <= '2014-11-30' AND preparedate >= '2014-11-01'
and prepareby = employeeid
group by employeeinfo.name

how to count days between two dates with where conditions

i have table and it has following data:
USERID NAME DATEFROM DATETO
1 xxx 2014-05-10 2014-05-15
1 xxx 2014-05-20 2014-05-25
4 yyy 2014-04-20 2014-04-21
now i have sql query like :
select * from leave where datefrom>='2014-05-01' and dateto<='2014-05-31'
so now i want output :
userid name total_leave_days
1 xxx 12
4 yyy 2
(2014-05-10 - 2014-05-15 )=6 days
(2014-05-20 - 2014-05-25 )=6 days
total = 12 days for useid 1
(2014-04-20 - 2014-04-21)= 2 days for userid 4
how can i calculate this total days .?
Please try:
select
USERID,
NAME,
SUM(DATEDIFF(day, DATEFROM, DATETO)+1) total_leave_days
From leave
group by USERID, NAME
SQL Fiddle Demo
It's important to note that you need "+1" to emulate the expected calculations because there is an inherent assumption of ""start of day" for the Start date and "end of day" for end date - but dbms's don't think that way. a date is always stored as "start of day".
select
USERID
, name
, sum( datediff(day,DATEFROM,DATETO) + 1 ) as leave_days
from leavetable
group by
USERID
, name
produces this:
| USERID | NAME | LEAVE_DAYS |
|--------|------|------------|
| 1 | xxx | 12 |
| 4 | yyy | 2 |
see: http://sqlfiddle.com/#!3/ebe5d/1
You can use DateDiff.
SELECT UserID, Name, SUM(DATEDIFF(DAY, DateFrom, DateTo) + 1) AS total_leave_days
FROM leave
WHERE datefrom >= '2014-05-01' AND dateto <= '2014-05-31'
GROUP BY UserID, Name
The + 1 ,of course, is because DATEDIFF will return the exclusive count, where it sounds like you want the inclusive number of days.
Try this:
select userid, name, sum (1 + datediff(day,datefrom,dateto)) as total_leave_days
from leaves
where datefrom>='2014-05-01' and dateto<='2014-05-31'
group by userid, name
This will sum the total leaves per userid. Note that datediff will give you 5 days difference for the range 2014-05-10 to 2014-05-15, so we need to add 1 to the result to get 6 days i.e. range inclusive of both ends.
Demo