Find difference between rows of same column (difference between time data) - asp.net

I want to find difference between time data which is in same column for group of same employee. I have written a query as below:
WITH rows AS
(
SELECT isnull(left(hhmm,2)+ ':'+ right(left(hhmm,4),2),'''') as login,
ROW_NUMBER() OVER (ORDER BY cardno) AS rn
FROM ATTN01072013_copy13_7_13
)
SELECT *--mc.login-mp.login as diff
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn - 1
This query will return data like this:
cardno login rn cardno login rn
E44920 09:18 1 E44920 09:46 2
E44920 09:46 2 E44920 17:09 3
E44920 17:09 3 E44920 16:57 4
E44920 16:57 4 E44920 17:34 5
E44920 17:34 5 E44920 17:53 6
E44920 17:53 6 E44920 17:56 7
E44920 17:56 7 E44920 17:57 8
E44920 17:57 8 E44920 18:00 9
Now I want to find difference between 1st and 2nd login time.. then 3rd and 4th login time. How can I do this, kindly suggest solution asap, thanks.

Solution:
DECLARE #Event TABLE(
EventID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
CardNo VARCHAR(10) NOT NULL,
[Login] DATETIME NOT NULL
-- To prevent duplicate events
-- This constraint will create an index used to optimize the RowNum and the last queries
UNIQUE(CardNo,[Login])
);
INSERT INTO #Event(CardNo,[Login])
SELECT 'E44920', '2013-07-15T09:18:00'
UNION ALL SELECT 'E44920', '2013-07-15T09:46:00'
UNION ALL SELECT 'E44920', '2013-07-15T17:09:00'
UNION ALL SELECT 'E44920', '2013-07-15T16:57:00'
UNION ALL SELECT 'E44920', '2013-07-15T17:34:00'
UNION ALL SELECT 'E44920', '2013-07-15T17:53:00';
DECLARE #EventWithRowNum TABLE(
RowNum INT NOT NULL,
CardNo VARCHAR(10) NOT NULL,
PRIMARY KEY (CardNo,RowNum),
[Login] DATETIME NOT NULL
UNIQUE(CardNo,[Login])
);
INSERT INTO #EventWithRowNum (CardNo,[Login],RowNum)
SELECT e.CardNo, e.[Login], ROW_NUMBER() OVER(PARTITION BY e.CardNo ORDER BY e.[Login]) AS RowNum
FROM #Event e;
-- Final query
SELECT crt.RowNum,
crt.CardNo,
crt.[Login] AS CurrentLogin,
nxt.RowNum,
nxt.[Login] AS NextLogin,
DATEDIFF(SECOND, crt.Login, nxt.Login) AS Diff_Seconds
FROM #EventWithRowNum crt -- crt = odd rows
LEFT JOIN #EventWithRowNum nxt ON crt.CardNo=nxt.CardNo AND crt.RowNum=nxt.RowNum-1 -- nxt = even rows
WHERE crt.RowNum % 2 = 1 -- odd rows; you could add a computed column Modulo2 AS (RowNum % 2) PERSISTED and then you could define a index (key: Modulo2, CardNo, Login)
ORDER BY crt.CardNo, crt.[Login];
Results:
RowNum CardNo Current_Login RowNum Next_Login Diff_Seconds
----------- ---------- ----------------------- ----------- ----------------------- ------------
1 E44920 2013-07-15 09:18:00.000 2 2013-07-15 09:46:00.000 1680
3 E44920 2013-07-15 16:57:00.000 4 2013-07-15 17:09:00.000 720
5 E44920 2013-07-15 17:34:00.000 6 2013-07-15 17:53:00.000 1140

Try:
DATEDIFF (mi, CAST(mc.login AS DATETIME), CAST(mp.login AS DATETIME)) as diff
This will get difference in minutes
SQLFiddle DEMO

Here is a fully query you can try using. As Nenad Zivkovic already shown, idea is to use DATEDIFF function for this.
Only difference is that I’d suggest using full date time for calculating the difference to avoid possible issues when one login is like 22:03 and other one is 00:16.
WITH rows AS
(
SELECT isnull(left(hhmm,2)+ ':'+ right(left(hhmm,4),2),'''') as login,
hhmm as Full_Login,
ROW_NUMBER() OVER (ORDER BY cardno) AS rn
FROM ATTN01072013_copy13_7_13
)
SELECT mc.login,
mc.rn,
DATEDIFF(mi,mc.Full_Login, mp.Full_Login)
mp.login,
mc.rn
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn

Related

Select Rows by Consecutive Dates in SQLite

I have a table with data like below:
Log Table:
User Id
Login Date
1
2022-01-03
1
2022-01-04
1
2022-01-10
1
2022-01-11
1
2022-01-12
1
2022-01-23
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
What I'm trying to do is to create a query that return rows of the latest logins by consecutive dates with var_date as parameter.
If var_date is 2022-01-29, then the result is:
User Id
Login Date
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
If var_date is 2022-01-30, then no result is returned, since 2022-01-29 is not in the table.
If var_date is 2022-01-24, then the query will return row with 2022-01-23 as login date.
How am I to do this in SQLite?
Thank you.
This question is a variant of gaps and islands, with the islands being clusters of records per user with continuous dates. Here is one approach using analytic functions:
WITH cte AS (
SELECT *, CASE WHEN julianday(LoginDate) -
julianday(LAG(LoginDate) OVER (PARTITION BY UserID
ORDER BY LoginDate))
> 1 THEN 1 ELSE 0 END AS counter
FROM yourTable
),
cte2 AS (
SELECT *, SUM(counter) OVER (PARTITION BY UserID ORDER BY LoginDate) AS grp
FROM cte
)
SELECT UserID, LoginDate
FROM cte2 t1
WHERE LoginDate < '2022-01-29' AND
grp = (SELECT t2.grp FROM cte2 t2
WHERE t2.UserID = t1.UserID AND t2.LoginDate = '2022-01-28');
Demo
The two CTEs generate a pseudo date group for each cluster per user. The final query returns all records less than the target date for which the group value is the same as the immediately preceding date. Hence, for dates having no immediate record for a given user, the query will return empty set.
Use a recursive CTE:
WITH cte(UserId, LoginDate) AS (
SELECT :var_user_id, :var_date
UNION ALL
SELECT UserId, date(c.LoginDate, '-1 day')
FROM cte c
WHERE EXISTS (SELECT 1 FROM tablename t WHERE t.UserId = c.UserId AND t.LoginDate = date(c.LoginDate, '-1 day'))
)
SELECT *
FROM cte
WHERE LoginDate < (SELECT MAX(LoginDate) FROM cte);
Change :var_user_id and :var_date to the values that you want for the user's id and the date.
See the demo.

how to join all the tables without using any condition

all the below results are not related to each other wheras we cannot use any condition.
ID
----------
1
2
3
4
5
6
7
7 rows selected.
NAME
-----------------
SRUJAN
DEERAJ
VINEETH
CHANIKYA
LAVANYA
KAVITHA
BUNNY
7 rows selected.
AGE
----------
23
24
26
25
29
28
24
7 rows selected.
ADDRESS
-------------
NAGARAM
BANDLAGUDA
UPPAL
KUKATPALLY
HB COLONY
MOULALI
BOUDHA NAGAR
7 rows selected.
SALARY
----------
12000
13000
14000
15000
16000
17000
18000
7 rows selected.
I USED
SQL>select id,name,age,address,salary from table1,table2,table3,table4,table5;
but it showing 16807 rows selected
i want to get only one table.
please suggest a query.
The only possible join between 2 tables having only 1 columns and both having no relation is cross join. You cannot avoid it. And the same you are getting when you tried to join. The best way for you is to create a sequence as ID and then call it in your select statement of table2.
CREATE SEQUENCE TEST_SEQ
START WITH 1
MAXVALUE 9999999999999999999999999999
MINVALUE 1
NOCYCLE;
select TEST_SEQ.nextval ID,col1 NAME
from table2;
Here is one way, using inner joins. This solution matches the lowest id with the first name in alphabetical order, the lowest age, etc.
If instead of this ordered matching you need random matching, that is easy to do as well: in the over... clause of the prep tables, change the order by clause to order by dbms_random.value() (in all places).
In the solution below I use only the first three tables, but the same works for any number of input tables.
with
tbl_id ( id ) as (
select 1 from dual union all
select 2 from dual union all
select 3 from dual union all
select 4 from dual union all
select 5 from dual union all
select 6 from dual union all
select 7 from dual
),
tbl_name ( name ) as (
select 'SRUJAN' from dual union all
select 'DEERAJ' from dual union all
select 'VINEETH' from dual union all
select 'CHANIKYA' from dual union all
select 'LAVANYA' from dual union all
select 'KAVITHA' from dual union all
select 'BUNNY' from dual
),
tbl_age ( age ) as (
select 23 from dual union all
select 24 from dual union all
select 26 from dual union all
select 25 from dual union all
select 29 from dual union all
select 28 from dual union all
select 24 from dual
),
prep_id ( id, rn ) as (
select id, row_number() over (order by id) from tbl_id
),
prep_name ( name, rn ) as (
select name, row_number() over (order by name) from tbl_name
),
prep_age ( age , rn ) as (
select age, row_number() over (order by age) from tbl_age
)
select i.id, n.name, a.age
from prep_id i inner join prep_name n on i.rn = n.rn
inner join prep_age a on i.rn = a.rn
;
Output:
ID NAME AGE
---------- -------- ----------
1 BUNNY 23
2 CHANIKYA 24
3 DEERAJ 24
4 KAVITHA 25
5 LAVANYA 26
6 SRUJAN 28
7 VINEETH 29
7 rows selected

Oracle Timestamp based calculation on every day using Two datetime column

I have a table that contains two time stamp t1(event open date) and t2(event close date) and a primary key eventid.
If event is open then t2 will be null whenever even gets closed the same row will be get updated with event closure date t2.
For example I want to check how many issues are open on every day bases on opened date (t1) from 01-apr-2016 to 10-apr-2016.
I have to calculate how many events are open for every day based on a selected date range.
Lets say if eventid 1 has got opened on 1st-APR and got closed on 10th-APR and I am calculating the number of opened issues for every day on 11th-APR then it should give me number of open event 1 from 1st-APR to 10th-APR.
Table Structure:-
================================================
EVENTID T1 T2
================================================
1 01-apr-2016 10-apr-2016
2 02-apr-2016 08-apr-2016
3 05-apr-2016 09-apr-2016
Expected Output:-
==============================================================================
DATE TOTAL_OPEN_EVENTS
==============================================================================
01-apr-2016 1
02-apr-2016 2(1 issue open on 1st(not closed on 2nd) and 1 on 2nd)
03-apr-2016 2
04-apr-2016 2
05-apr-2016 3
06-apr-2016 3
07-apr-2016 3
08-apr-2016 2(1 issue got closed on 8th(which was opened on 2nd))
09-apr-2016 2
10-apr-2016 0
How to do this kind of calculation in Oracle database ?
In order to generate the end report, you need a row for each date in your desired range. You could either use a calendar table, if available, or I find using a query on DUAL using CONNECT BY LEVEL < some_number works well to generate rows on the fly. (In this case "some_number" will be the number of days you want to report on.)
From there, you just need to join the individual dates to the date ranges in your event table:
-- create table "events" table
create table event_date_ranges
as
select 1 as event_id, TO_DATE('2016-APR-01', 'YYYY-MM-DD') as start_date, TO_DATE('2016-APR-10', 'YYYY-MON-DD') as end_date from dual
union all
select 2 as event_id, TO_DATE('2016-APR-02', 'YYYY-MM-DD') as start_date, TO_DATE('2016-APR-08', 'YYYY-MON-DD') as end_date from dual
union all
select 3 as event_id, TO_DATE('2016-APR-05', 'YYYY-MM-DD') as start_date, TO_DATE('2016-APR-09', 'YYYY-MON-DD') as end_date from dual
;
with
date_range_qry as
(-- one way to set the start and end dates for your report
select TO_DATE('2016-APR-01', 'YYYY-MM-DD') as report_start_date
, TO_DATE('2016-APR-10', 'YYYY-MM-DD') as report_end_date
from dual
)
, dates_qry
as
(
-- generate a row for all dates between 2016-APR-01 and 2016-APR-10
select report_start_date + ROWNUM - 1 as report_date
from dual
cross join
date_range_qry drq
connect by level <= (drq.report_end_date - drq.report_start_date + 1)
)
select dq.report_date, count(edr.event_id) as total_open_events
from dates_qry dq
left outer join
event_date_ranges edr
on dq.report_date >= edr.start_date
and dq.report_date < edr.end_date
group by dq.report_date
order by dq.report_date
Output:
REPORT_DATE TOTAL_OPEN_EVENTS
2016-APR-01 1
2016-APR-02 2
2016-APR-03 2
2016-APR-04 2
2016-APR-05 3
2016-APR-06 3
2016-APR-07 3
2016-APR-08 2
2016-APR-09 1
2016-APR-10 0
You can try this:
create table events_log
as
select 1 as event_id, TO_DATE('01-04-2016', 'DD/MM/YYYY') as T1, TO_DATE('10-04-2016', 'DD/MM/YYYY') as T2 from dual
union all
select 2 as event_id, TO_DATE('02-04-2016', 'DD/MM/YYYY') as T1, TO_DATE('08-04-2016', 'DD/MM/YYYY') as T2 from dual
union all
select 3 as event_id, TO_DATE('05-04-2016', 'DD/MM/YYYY') as T1, TO_DATE('09-04-2016', 'DD/MM/YYYY') as T2 from dual
;
--------------
select v.REPORT_DATE, count(t.EVENT_ID) as open_event
from events_log t,
(select to_date('01/04/2016', 'DD/MM/YYYY') + ROWNUM - 1 as report_date
from dual
connect by level <= (to_date('11/04/2016', 'DD/MM/YYYY') -
to_date('01/04/2016', 'DD/MM/YYYY') + 1)) v
where t.T1(+) <= v.report_date
and t.T2(+) >= v.report_date
group by v.report_date
order by v.report_date;
Output will be:
report_date open_event
01/04/2016 1
02/04/2016 2
03/04/2016 2
04/04/2016 2
05/04/2016 3
06/04/2016 3
07/04/2016 3
08/04/2016 3
09/04/2016 2
10/04/2016 1
11/04/2016 0

Group by function column

I'm writing a query like this...
select to_char(e_date, 'MON/YYYY') as Month , location_code, count(employee_number) from...
Now I want to group by Month and Location_code. so how to use to_char(e_date, 'MON/YYYY') as Month in group by clause?
EDIT:
select to_char(vheda.e_date, 'MON/YYYY') as Months , hla.location_code, count(vheda.employee_number) emp_count from
virtu.virt_hr_emp_daily_attendance vheda
inner join per_all_people_f papf on vheda.party_id = papf.party_id
inner join per_all_assignments_f paaf on papf.person_id = paaf.person_id
inner join hr_locations_all hla on paaf.location_id = hla.location_id
where (trunc(sysdate) between PAPF.EFFECTIVE_START_DATE and PAPF.EFFECTIVE_END_DATE)
--and (vheda.e_in_time is not null)
and vheda.e_duration <> 0
and (trunc(sysdate) between PAAF.EFFECTIVE_START_DATE and PAAF.EFFECTIVE_END_DATE)
and vheda.e_date between '1-aug-2014' and '31-oct-2014'
group by hla.location_code, vheda.e_date
order by vheda.e_date
OUT PUT WHEN USE GROUP BY CLAUSE group by to_char(vheda.e_date, 'MON/YYYY'), hla.location_code:
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 58 Column: 37
select to_char(e_date, 'MON/YYYY') as Month , location_code, count(employee_number)
from ...
group by to_char(e_date, 'MON/YYYY'), location_code
You need to group by To_char(vheda.e_date, 'MON/YYYY') and hla.location_code.
SELECT To_char(vheda.e_date, 'MON/YYYY') AS Months,
hla.location_code,
Count(vheda.employee_number) emp_count
FROM virtu.virt_hr_emp_daily_attendance vheda
inner join per_all_people_f papf
ON vheda.party_id = papf.party_id
inner join per_all_assignments_f paaf
ON papf.person_id = paaf.person_id
inner join hr_locations_all hla
ON paaf.location_id = hla.location_id
WHERE ( Trunc(SYSDATE) BETWEEN PAPF.effective_start_date AND
PAPF.effective_end_date )
--and (vheda.e_in_time is not null)
AND vheda.e_duration <> 0
AND ( Trunc(SYSDATE) BETWEEN PAAF.effective_start_date AND
PAAF.effective_end_date )
AND vheda.e_date BETWEEN '1-aug-2014' AND '31-oct-2014'
GROUP BY To_char(vheda.e_date, 'MON/YYYY'),
hla.location_code
ORDER BY vheda.e_date
For example, let's see the same with EMP table,
SQL> SELECT To_char(hiredate, 'MON/YYYY') AS Months,
2 deptno,
3 Count(empno) emp_count
4 FROM emp
5 GROUP BY To_char(hiredate, 'MON/YYYY'),
6 deptno
7 /
MONTHS DEPTNO EMP_COUNT
-------- ---------- ----------
DEC/1980 20 1
JUN/1981 10 1
NOV/1981 10 1
MAY/1987 20 1
FEB/1981 30 2
MAY/1981 30 1
DEC/1981 30 1
JAN/1982 10 1
SEP/1981 30 2
DEC/1981 20 1
APR/1981 20 1
APR/1987 20 1
12 rows selected.
SQL>
select EXTRACT(MONTH FROM e_date)||'/'|| EXTRACT(Year FROM e_date) as months , location_code, count(employee_number)
FROM ...
group by EXTRACT(MONTH FROM e_date)||'/'|| EXTRACT(Year FROM e_date), location_code
You can also use EXTRACT function in GROUP BY clause..
i hope it helps..

column is amguously defined in column

my tables
DESC emp
Name Null Type
------------------------------ -------- --------------------------
EMP_NO NUMBER
EMP_NAME VARCHAR2(10)
ADDRESS VARCHAR2(15)
PH_NO NUMBER(10)
DEPT_NO NUMBER
result:
1 ram ctr 8892939927 100
2 mohan ptr 7569936347 101
3 mallu ppt 9553438342 102
4 scoot dmc 9874563210 103
5 jim plr 9236548875 104
6 ravi tpt 8562398756 105
7 manju hyd 7562398742 106
8 manoj hyd 869523654 107
9 sarath ctr 9632158769 108
10 hemanth mpk 9632147852 109
desc salary
Name Null Type
------------------------------ -------- --------------------------
EMP_NO NUMBER
SALARY NUMBER(10)
PERIOD VARCHAR2(10)
START_DATE DATE
END_DATE DATE
result:
1 12580 15months 12-DEC-07 10-DEC-10
2 15500 19months 10-JAN-07 10-DEC-11
3 7777 18months 11-JUL-07 21-APR-11
4 9999 11months 07-JUL-07 31-JAN-11
5 8500 9months 12-MAR-07 27-MAR-11
6 10000 20months 17-SEP-07 01-AUG-11
7 25000 7months 17-NOV-07 26-JUL-11
8 100000 6months 05-MAY-07 21-JUN-11
9 35000 16months 28-FEB-08 21-JUN-11
10 5000 16months 02-DEC-08 19-AUG-11
joinning query :
select emp_no,
emp_name,
dpt_no,
salary
from emp
join salary on emp.dpt_no=salary.dpt_no
but am getting error is"column is amguously defined". How to resolve this problem?
You need to fully qualify the columns in the select list (the way it's done in the JOIN condition). Otherwise Oracle wouldn't know from which table the column dept_no should be taken.
select emp.emp_no,
emp.emp_name,
emp.dpt_no,
salary.salary
from emp
join salary on emp.dpt_no=salary.dpt_no;
It's good coding style to always qualify the columns - at least in a query involving more than one table - even if they are not ambigous.
If you don't want to type the full table name, you can use a (maningful) alias:
select emp.emp_no,
emp.emp_name,
emp.dpt_no,
sal.salary,
sal.period
from emp
join salary sal
on emp.dpt_no = sal.dpt_no;
If the columnname is the same in tables (salary and emp) and youre joining the tables, you have to specify form wich table you want to selecte the column (salary or from emp)
in youre case the solution is to use salary.dpt_no instead of dpt_no
select emp_no,emp_name, salary.dpt_no,salary from emp join salary on emp.dpt_no=salary.dpt_no

Resources