Right join multiple key where mutiple key is null - sql

I need help from captain obvious I suppose. I'm trying to Insert data from a table into a temptable. Ok this is easy
I need to insert the data we got today and the data we got 10 days ago. The where clause may aford it, th's okay
What for me is hard is to insert the data of today only if it does not appear in the data 10 days ago
An exemple of the table I use ([datatable]) :
Date Purchase Line_Purchase
---------------------------------------------------------------------------
2017-04-29 0000002 01
2017-04-29 0000002 02
2017-04-29 0000003 01
2017-04-29 0000003 02
2017-04-29 0000003 03
2017-04-29 0000004 01
2017-04-29 0000005 01
2017-04-19 0000001 01
2017-04-19 0000001 02
2017-04-19 0000001 03
2017-04-19 0000002 01
2017-04-19 0000002 02
My desired table temptable:
Input_date Purchase Line_Purchase
-------------------------------------------------------------------------
2017-04-19 0000001 01
2017-04-19 0000001 02
2017-04-19 0000001 03
2017-04-19 0000002 01
2017-04-19 0000002 02
2017-04-29 0000003 01
2017-04-29 0000003 02
2017-04-29 0000003 03
2017-04-29 0000004 01
2017-04-29 0000005 01
Is there any request possible in SQL that can change that ?
I tried this way
INSERT INTO #TEMPTABLE
(Input_date ,Purchase ,Line_Purchase)
SELECT
table.Date
,table.Purchase
,table.Line_Purchase
FROM
datatable table
WHERE
convert(date, table.Date) = convert(date, GETDATE() - 10)
INSERT INTO #TEMPTABLE
(Input_date ,Purchase ,Line_Purchase)
SELECT
table.Date
,table.Purchase
,table.Line_Purchase
FROM
datatable table
RIGHT JOIN #TEMPTABLE temp
on table.Purchase = temp.Purchase and table.Line_Purchase = temp.Line_Purchase
WHERE
convert(date, table.Date) = convert(date, GETDATE())
AND (temp.Purchase is null AND temp.Line_Purchase is null)
Thanks in advance

You can do this with not exists():
select date as Input_date, Purchase, Line_Purchase
into #temptable
from t
where date = '2017-04-19' --convert(date, getdate() - 10);
insert into #temptable (Input_date, Purchase, Line_Purchase)
select *
from t
where date = '2017-04-29'
and not exists (
select 1
from t as i
where i.purchase=t.purchase
and i.line_purchase=t.line_purchase
and i.date = '2017-04-19' --convert(date, getdate() - 10)
);
select *
from #temptable;
rextester demo: http://rextester.com/SAQSG21367
returns:
+------------+----------+---------------+
| Input_Date | Purchase | Line_Purchase |
+------------+----------+---------------+
| 2017-04-19 | 0000001 | 01 |
| 2017-04-19 | 0000001 | 02 |
| 2017-04-19 | 0000001 | 03 |
| 2017-04-19 | 0000002 | 01 |
| 2017-04-19 | 0000002 | 02 |
| 2017-04-29 | 0000003 | 01 |
| 2017-04-29 | 0000003 | 02 |
| 2017-04-29 | 0000003 | 03 |
| 2017-04-29 | 0000004 | 01 |
| 2017-04-29 | 0000005 | 01 |
+------------+----------+---------------+
Optionally, if you are doing both of these operations at the same time you can do it in the same query using a derived table/subquery or common table expression with row_number()
;
;with cte as (
select date, Purchase, Line_Purchase
, rn = row_number() over (partition by Purchase,Line_Purchase order by date)
from t
--where date in ('2017-09-26','2017-09-16')
where date in (convert(date, getdate()), convert(date, getdate()-10))
)
select date as Input_date, Purchase, Line_Purchase
into #temptable
from cte
where rn = 1
select *
from #temptable;
rextester demo: http://rextester.com/QMF5992
returns:
+------------+----------+---------------+
| Input_date | Purchase | Line_Purchase |
+------------+----------+---------------+
| 2017-09-16 | 0000001 | 01 |
| 2017-09-16 | 0000001 | 02 |
| 2017-09-16 | 0000001 | 03 |
| 2017-09-16 | 0000002 | 01 |
| 2017-09-16 | 0000002 | 02 |
| 2017-09-26 | 0000003 | 01 |
| 2017-09-26 | 0000003 | 02 |
| 2017-09-26 | 0000003 | 03 |
| 2017-09-26 | 0000004 | 01 |
| 2017-09-26 | 0000005 | 01 |
+------------+----------+---------------+

Related

How do I edit the code that calculates the value for the four weeks of the month for all months with pl/sql?

I divided the month into four weeks and printed the amount for each week. How do I set this up with a loop for 12 months?
declare
cursor c is
select varis_tar, tutar
from muhasebe.doviz_takip
where trunc(varis_tar) BETWEEN TO_DATE('01/10/2021', 'DD/MM/YYYY') AND
TO_DATE('31/10/2021', 'DD/MM/YYYY')
group by varis_tar,tutar;
tutar1 number(13,2):=0;
tutar2 number(13,2):=0;
tutar3 number(13,2):=0;
tutar4 number(13,2):=0;
begin
for r in c loop
if r.varis_tar between TO_DATE('01/10/2021', 'DD/MM/YYYY') AND
TO_DATE('07/10/2021', 'DD/MM/YYYY') then
tutar1:=(r.tutar)+tutar1;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('07/10/2021', 'DD/MM/YYYY') AND
TO_DATE('14/10/2021', 'DD/MM/YYYY') then
tutar2:=(r.tutar)+tutar2;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('14/10/2021', 'DD/MM/YYYY') AND
TO_DATE('21/10/2021', 'DD/MM/YYYY') then
tutar3:=(r.tutar)+tutar3;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('21/10/2021', 'DD/MM/YYYY') AND
TO_DATE('31/10/2021', 'DD/MM/YYYY') then
tutar4:=(r.tutar)+tutar4;
--message(r.tutar);
end if;
end loop;
I tried to get the dates the same way for all the months. I tried that, but it worked wrong.
where trunc(varis_tar) BETWEEN TO_DATE('1', 'DD') AND
TO_DATE('31', 'DD')
if r.varis_tar between TO_DATE('1', 'DD') AND
TO_DATE('07', 'DD') then
elsif r.varis_tar between TO_DATE('7', 'DD') AND
TO_DATE('14', 'DD') then
elsif r.varis_tar between TO_DATE('14', 'DD') AND
TO_DATE('21', 'DD') then
elsif r.varis_tar between TO_DATE('21', 'DD') AND
TO_DATE('31', 'DD') then
I don't know if I'am understanding it correctly but:
try if extract(day from varis_tar) between 1 and 7
or more complex
l_week := to_char(varis_tar,'W'); --week number
if l_week = 1 then --first week
elsif l_week = 2 etc...
Your code has several issues:
date in Oracle is actually a datetime, so between will not count any time after the midnight of the upper boundary.
you count the midnight of the week's end twice: in current week and in the next week (between includes both boundaries).
you do not need any PL/SQL and especially a cursor loop, because it occupy resources during calculation outside of SQL context.
Use datetime format to calculate weeks, because it is easy to read and understand. Then group by corresponding components.
with a as (
select
date '2021-01-01' - 1 + level as dt
, level as val
from dual
connect by level < 400
)
, b as (
select
dt
, val
/*Map 29, 30 and 31 to 28*/
, to_char(
least(dt, trunc(dt, 'mm') + 27)
, 'yyyymmw'
) as w
from a
)
select
substr(w, 1, 4) as y
, substr(w, 5, 2) as m
, substr(w, -1) as w
, sum(val) as val
, min(dt) as dt_from
, max(dt) as dt_to
from b
group by
w
Y | M | W | VAL | DT_FROM | DT_TO
:--- | :- | :- | ---: | :--------- | :---------
2021 | 01 | 1 | 28 | 2021-01-01 | 2021-01-07
2021 | 01 | 2 | 77 | 2021-01-08 | 2021-01-14
2021 | 01 | 3 | 126 | 2021-01-15 | 2021-01-21
2021 | 01 | 4 | 265 | 2021-01-22 | 2021-01-31
2021 | 02 | 1 | 245 | 2021-02-01 | 2021-02-07
2021 | 02 | 2 | 294 | 2021-02-08 | 2021-02-14
2021 | 02 | 3 | 343 | 2021-02-15 | 2021-02-21
2021 | 02 | 4 | 392 | 2021-02-22 | 2021-02-28
2021 | 03 | 1 | 441 | 2021-03-01 | 2021-03-07
2021 | 03 | 2 | 490 | 2021-03-08 | 2021-03-14
2021 | 03 | 3 | 539 | 2021-03-15 | 2021-03-21
2021 | 03 | 4 | 855 | 2021-03-22 | 2021-03-31
2021 | 04 | 1 | 658 | 2021-04-01 | 2021-04-07
2021 | 04 | 2 | 707 | 2021-04-08 | 2021-04-14
2021 | 04 | 3 | 756 | 2021-04-15 | 2021-04-21
2021 | 04 | 4 | 1044 | 2021-04-22 | 2021-04-30
2021 | 05 | 1 | 868 | 2021-05-01 | 2021-05-07
2021 | 05 | 2 | 917 | 2021-05-08 | 2021-05-14
2021 | 05 | 3 | 966 | 2021-05-15 | 2021-05-21
2021 | 05 | 4 | 1465 | 2021-05-22 | 2021-05-31
2021 | 06 | 1 | 1085 | 2021-06-01 | 2021-06-07
2021 | 06 | 2 | 1134 | 2021-06-08 | 2021-06-14
2021 | 06 | 3 | 1183 | 2021-06-15 | 2021-06-21
2021 | 06 | 4 | 1593 | 2021-06-22 | 2021-06-30
2021 | 07 | 1 | 1295 | 2021-07-01 | 2021-07-07
2021 | 07 | 2 | 1344 | 2021-07-08 | 2021-07-14
2021 | 07 | 3 | 1393 | 2021-07-15 | 2021-07-21
2021 | 07 | 4 | 2075 | 2021-07-22 | 2021-07-31
2021 | 08 | 1 | 1512 | 2021-08-01 | 2021-08-07
2021 | 08 | 2 | 1561 | 2021-08-08 | 2021-08-14
2021 | 08 | 3 | 1610 | 2021-08-15 | 2021-08-21
2021 | 08 | 4 | 2385 | 2021-08-22 | 2021-08-31
2021 | 09 | 1 | 1729 | 2021-09-01 | 2021-09-07
2021 | 09 | 2 | 1778 | 2021-09-08 | 2021-09-14
2021 | 09 | 3 | 1827 | 2021-09-15 | 2021-09-21
2021 | 09 | 4 | 2421 | 2021-09-22 | 2021-09-30
2021 | 10 | 1 | 1939 | 2021-10-01 | 2021-10-07
2021 | 10 | 2 | 1988 | 2021-10-08 | 2021-10-14
2021 | 10 | 3 | 2037 | 2021-10-15 | 2021-10-21
2021 | 10 | 4 | 2995 | 2021-10-22 | 2021-10-31
2021 | 11 | 1 | 2156 | 2021-11-01 | 2021-11-07
2021 | 11 | 2 | 2205 | 2021-11-08 | 2021-11-14
2021 | 11 | 3 | 2254 | 2021-11-15 | 2021-11-21
2021 | 11 | 4 | 2970 | 2021-11-22 | 2021-11-30
2021 | 12 | 1 | 2366 | 2021-12-01 | 2021-12-07
2021 | 12 | 2 | 2415 | 2021-12-08 | 2021-12-14
2021 | 12 | 3 | 2464 | 2021-12-15 | 2021-12-21
2021 | 12 | 4 | 3605 | 2021-12-22 | 2021-12-31
2022 | 01 | 1 | 2583 | 2022-01-01 | 2022-01-07
2022 | 01 | 2 | 2632 | 2022-01-08 | 2022-01-14
2022 | 01 | 3 | 2681 | 2022-01-15 | 2022-01-21
2022 | 01 | 4 | 3915 | 2022-01-22 | 2022-01-31
2022 | 02 | 1 | 1194 | 2022-02-01 | 2022-02-03
db<>fiddle here
Or the same in columns:
with a as (
select
date '2021-01-01' - 1 + level as dt
, level as val
from dual
connect by level < 400
)
, b as (
select
val
/*Map 29, 30 and 31 to 28*/
, to_char(dt, 'yyyymm') as m
, to_char(
least(dt, trunc(dt, 'mm') + 27)
, 'w'
) as w
from a
)
select
substr(m, 1, 4) as y
, substr(m, 5, 2) as m
, tutar1
, tutar2
, tutar3
, tutar4
from b
pivot(
sum(val)
for w in (
1 as tutar1, 2 as tutar2
, 3 as tutar3, 4 as tutar4
)
)
Y | M | TUTAR1 | TUTAR2 | TUTAR3 | TUTAR4
:--- | :- | -----: | -----: | -----: | -----:
2021 | 01 | 28 | 77 | 126 | 265
2021 | 02 | 245 | 294 | 343 | 392
2021 | 03 | 441 | 490 | 539 | 855
2021 | 04 | 658 | 707 | 756 | 1044
2021 | 05 | 868 | 917 | 966 | 1465
2021 | 06 | 1085 | 1134 | 1183 | 1593
2021 | 07 | 1295 | 1344 | 1393 | 2075
2021 | 08 | 1512 | 1561 | 1610 | 2385
2021 | 09 | 1729 | 1778 | 1827 | 2421
2021 | 10 | 1939 | 1988 | 2037 | 2995
2021 | 11 | 2156 | 2205 | 2254 | 2970
2021 | 12 | 2366 | 2415 | 2464 | 3605
2022 | 01 | 2583 | 2632 | 2681 | 3915
2022 | 02 | 1194 | null | null | null
db<>fiddle here

How to deduplicate table rows with the same date and keep the row with the most current date stamp?

A client (e-commerce store) doesn't possess a very well-built database. For instance, there are many users with a lot of shopping orders (=different IDs) for exactly the same products and on the same day. It is obvious that these seemingly multiple orders are in many cases just one unique order. At least that's what we have decided to work with to simplify the issue. (I am trying to do a basic data analytics.)
My table might look like this:
| Email | OrderID | Order_date | TotalAmount |
| ----------------- | --------- | ---------------- | ---------------- |
|customerA#gmail.com| 1 |Jan 01 2021 1:00PM| 2000 |
|customerA#gmail.com| 2 |Jan 01 2021 1:03PM| 2000 |
|customerA#gmail.com| 3 |Jan 01 2021 1:05PM| 2000 |
|customerA#gmail.com| 4 |Jan 01 2021 1:10PM| 2000 |
|customerA#gmail.com| 5 |Jan 01 2021 1:14PM| 2000 |
|customerA#gmail.com| 6 |Jan 03 2021 3:55PM| 3000 |
|customerA#gmail.com| 7 |Jan 03 2021 4:00PM| 3000 |
|customerA#gmail.com| 8 |Jan 03 2021 4:05PM| 3000 |
|customerB#gmail.com| 9 |Jan 04 2021 2:10PM| 1000 |
|customerB#gmail.com| 10 |Jan 04 2021 2:20PM| 1000 |
|customerB#gmail.com| 11 |Jan 04 2021 2:30PM| 1000 |
|customerB#gmail.com| 12 |Jan 06 2021 5:00PM| 5000 |
|customerC#gmail.com| 13 |Jan 09 2021 3:00PM| 4000 |
|customerC#gmail.com| 14 |Jan 09 2021 3:06PM| 4000 |
And my desired result would look like this:
| Email | OrderID | Order_date | TotalAmount |
| ----------------- | --------- | ---------------- | ---------------- |
|customerA#gmail.com| 5 |Jan 01 2021 1:14PM| 2000 |
|customerA#gmail.com| 8 |Jan 03 2021 4:05PM| 3000 |
|customerA#gmail.com| 11 |Jan 04 2021 2:30PM| 1000 |
|customerA#gmail.com| 12 |Jan 06 2021 5:00PM| 5000 |
|customerA#gmail.com| 14 |Jan 09 2021 3:06PM| 4000 |
I would guess this might be a common problem, but is there a simple solution to this?
Maybe there is, but I certainly don't seem to come up with one any time soon. I'd like to see even a complex solution, btw :-)
Thank you for any kind of help you can provide!
Do you mean this?
WITH
indata(Email,OrderID,Order_ts,TotalAmount) AS (
SELECT 'customerA#gmail.com', 1,TO_TIMESTAMP( 'Jan 01 2021 01:00PM','Mon DD YYYY HH12:MIAM'),2000
UNION ALL SELECT 'customerA#gmail.com', 2,TO_TIMESTAMP( 'Jan 01 2021 01:03PM','Mon DD YYYY HH12:MIAM'),2000
UNION ALL SELECT 'customerA#gmail.com', 3,TO_TIMESTAMP( 'Jan 01 2021 01:05PM','Mon DD YYYY HH12:MIAM'),2000
UNION ALL SELECT 'customerA#gmail.com', 4,TO_TIMESTAMP( 'Jan 01 2021 01:10PM','Mon DD YYYY HH12:MIAM'),2000
UNION ALL SELECT 'customerA#gmail.com', 5,TO_TIMESTAMP( 'Jan 01 2021 01:14PM','Mon DD YYYY HH12:MIAM'),2000
UNION ALL SELECT 'customerA#gmail.com', 6,TO_TIMESTAMP( 'Jan 03 2021 03:55PM','Mon DD YYYY HH12:MIAM'),3000
UNION ALL SELECT 'customerA#gmail.com', 7,TO_TIMESTAMP( 'Jan 03 2021 04:00PM','Mon DD YYYY HH12:MIAM'),3000
UNION ALL SELECT 'customerA#gmail.com', 8,TO_TIMESTAMP( 'Jan 03 2021 04:05PM','Mon DD YYYY HH12:MIAM'),3000
UNION ALL SELECT 'customerB#gmail.com', 9,TO_TIMESTAMP( 'Jan 04 2021 02:10PM','Mon DD YYYY HH12:MIAM'),1000
UNION ALL SELECT 'customerB#gmail.com',10,TO_TIMESTAMP( 'Jan 04 2021 02:20PM','Mon DD YYYY HH12:MIAM'),1000
UNION ALL SELECT 'customerB#gmail.com',11,TO_TIMESTAMP( 'Jan 04 2021 02:30PM','Mon DD YYYY HH12:MIAM'),1000
UNION ALL SELECT 'customerB#gmail.com',12,TO_TIMESTAMP( 'Jan 06 2021 05:00PM','Mon DD YYYY HH12:MIAM'),5000
UNION ALL SELECT 'customerC#gmail.com',13,TO_TIMESTAMP( 'Jan 09 2021 03:00PM','Mon DD YYYY HH12:MIAM'),4000
UNION ALL SELECT 'customerC#gmail.com',14,TO_TIMESTAMP( 'Jan 09 2021 03:06PM','Mon DD YYYY HH12:MIAM'),4000
)
,
-- need a ROW_NUMBER() to identify the last row within the day (order descending to get 1.
-- can't filter by an OLAP function, so in a fullselect, and WHERE cond in the final SELECT
with_rank AS (
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY email,DAY(order_ts) ORDER BY order_ts DESC) AS rank
FROM INDATA
)
SELECT
*
FROM with_rank
WHERE rank = 1;
-- out Email | OrderID | Order_ts | TotalAmount | rank
-- out ---------------------+---------+---------------------+-------------+------
-- out customerA#gmail.com | 5 | 2021-01-01 13:14:00 | 2000 | 1
-- out customerA#gmail.com | 8 | 2021-01-03 16:05:00 | 3000 | 1
-- out customerB#gmail.com | 11 | 2021-01-04 14:30:00 | 1000 | 1
-- out customerB#gmail.com | 12 | 2021-01-06 17:00:00 | 5000 | 1
-- out customerC#gmail.com | 14 | 2021-01-09 15:06:00 | 4000 | 1

Count duration of events and group in 24 hours intervals SQL

I have table with data of events contains two dates:
1) Event Start Date (eg. 2017-03-01 05:30:00)
2) Event End Date (eg. 2017-03-01 06:10:00)
I need create report with structure, where data are sum all events in given year-day and hour grouped in 24h time interval, like that:
Two rows:
Id | Start date | End date
Event 1 | 2017-03-01 07:45 | 2017-03-01 08:15
Event 2 | 2017-03-01 08:25 | 2017-03-01 08:40
And Query result:
Year-Month-Day | Hours | (Activity time in seconds or minutes - here minutes)
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 30
2017-03-01 | 09 | 00
...
Is elegant way to do this in Oracle SQL? I wrote some psudocode in first moment, (where I count diff between start and end time, check how many hours were affected, and assign to right interval) , but maybe exist more native and better performance solution - like aggregate functions or etc?
Thanks for help.
Here is a query that does what you need.
However note that this will only work for events that finish in 1 million minutes i.e. about 2 years.
WITH event
AS (SELECT 'Event 1' AS id,
'2017-03-01 07:45' AS start_date,
'2017-03-01 08:15' AS end_date
FROM DUAL
UNION ALL
SELECT 'Event 2' AS id,
'2017-03-01 08:25' AS start_date,
'2017-03-01 08:40' AS end_date
FROM DUAL),
add_mins
AS (SELECT LEVEL
- 1
AS add_min
FROM DUAL
CONNECT BY LEVEL <= 1000000),
hrs_in_day
AS (SELECT LEVEL
- 1
AS hr
FROM DUAL
CONNECT BY LEVEL <= 24),
all_days_hrs
AS (SELECT *
FROM (SELECT TO_CHAR (
(first_start_day
+ LEVEL
- 1),
'YYYY-MM-DD'
)
AS curr_day
FROM (SELECT MIN (curr_day) AS first_start_day,
MAX (curr_day) AS last_end_day
FROM (SELECT TO_TIMESTAMP (start_date, 'YYYY-MM-DD HH24:MI')
AS curr_day
FROM event
UNION
SELECT TO_TIMESTAMP (end_date, 'YYYY-MM-DD HH24:MI')
AS curr_day
FROM event))
CONNECT BY (first_start_day
+ LEVEL
- 1) < last_end_day),
hrs_in_day)
SELECT hl.curr_day AS year_month_day,
LPAD (hl.hr, 2, '0') AS hours,
COUNT (h.curr_hr) AS activity_duration_in_min
FROM all_days_hrs hl
LEFT JOIN
(SELECT id,
start_time,
end_time,
curr_time,
TO_CHAR (curr_time, 'YYYY-MM-DD') AS year_month_day,
EXTRACT (HOUR FROM curr_time) AS curr_hr
FROM (SELECT id,
start_time,
end_time,
b.add_min,
start_time
+ NUMTODSINTERVAL (b.add_min, 'minute')
AS curr_time
FROM (SELECT id,
start_time,
end_time,
EXTRACT (DAY FROM dur_interval) * 1440
+ EXTRACT (HOUR FROM dur_interval) * 60
+ EXTRACT (MINUTE FROM dur_interval)
AS duration_in_min
FROM (SELECT id,
start_time,
end_time,
(end_time
- start_time)
AS dur_interval
FROM (SELECT id,
TO_TIMESTAMP (
start_date,
'YYYY-MM-DD HH24:MI'
)
AS start_time,
TO_TIMESTAMP (
end_date,
'YYYY-MM-DD HH24:MI'
)
AS end_time
FROM event))) a,
add_mins b
WHERE b.add_min < a.duration_in_min)) h
ON (hl.curr_day = h.year_month_day
AND hl.hr = h.curr_hr)
GROUP BY hl.curr_day,
hl.hr
ORDER BY year_month_day NULLS FIRST,
hl.hr;
It is a bit slow though. I haven't spent any time thinking about performance.
But it works. Here is the output.
Year-Month-day | Hours | Activity_Duration_in_min
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 30
2017-03-01 | 09 | 0
2017-03-01 | 10 | 0
2017-03-01 | 11 | 0
2017-03-01 | 12 | 0
2017-03-01 | 13 | 0
2017-03-01 | 14 | 0
2017-03-01 | 15 | 0
2017-03-01 | 16 | 0
2017-03-01 | 17 | 0
2017-03-01 | 18 | 0
2017-03-01 | 19 | 0
2017-03-01 | 20 | 0
2017-03-01 | 21 | 0
2017-03-01 | 22 | 0
2017-03-01 | 23 | 0
And if we change the end date of 'Event 2' to 2017-03-02 (i.e. the event lasted one day and 15 min and 40 min in the 8th hour) we can see that the output changes to reflect the 48 hour duration.
Year-Month-day | Hours | Activity_Duration_in_min
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 50
2017-03-01 | 09 | 60
2017-03-01 | 10 | 60
2017-03-01 | 11 | 60
2017-03-01 | 12 | 60
2017-03-01 | 13 | 60
2017-03-01 | 14 | 60
2017-03-01 | 15 | 60
2017-03-01 | 16 | 60
2017-03-01 | 17 | 60
2017-03-01 | 18 | 60
2017-03-01 | 19 | 60
2017-03-01 | 20 | 60
2017-03-01 | 21 | 60
2017-03-01 | 22 | 60
2017-03-01 | 23 | 60
2017-03-02 | 00 | 60
2017-03-02 | 01 | 60
2017-03-02 | 02 | 60
2017-03-02 | 03 | 60
2017-03-02 | 04 | 60
2017-03-02 | 05 | 60
2017-03-02 | 06 | 60
2017-03-02 | 07 | 60
2017-03-02 | 08 | 40
2017-03-02 | 09 | 0
2017-03-02 | 10 | 0
2017-03-02 | 11 | 0
2017-03-02 | 12 | 0
2017-03-02 | 13 | 0
2017-03-02 | 14 | 0
2017-03-02 | 15 | 0
2017-03-02 | 16 | 0
2017-03-02 | 17 | 0
2017-03-02 | 18 | 0
2017-03-02 | 19 | 0
2017-03-02 | 20 | 0
2017-03-02 | 21 | 0
2017-03-02 | 22 | 0
2017-03-02 | 23 | 0

SQL Server : Insert blank line in query

This may be so last year but I'm using SQL Server 2005
stmpdate intime
----------------------
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:79:56
2014-10-17 07:45:56
I have this table. It keeps check-in time of the employee, but this employee didn't check-in everyday in the month. So what I want it to be is something like this
stmpdate intime
1 2014-10-01
2 2014-10-02
3 2014-10-03
4 2014-10-04
5 2014-10-05
6 2014-10-06
7 2014-10-07
8 2014-10-08 08:04:43
9 2014-10-09 07:57:13
10 2014-10-10 07:57:14
11 2014-10-11
12 2014-10-12
13 2014-10-13
14 2014-10-14
15 2014-10-15
16 2014-10-16 07:59:56
17 2014-10-17 07:45:56
18 2014-10-18
19 2014-10-19
20 2014-10-20
21 2014-10-21
22 2014-10-22
23 2014-10-23
24 2014-10-24
25 2014-10-25
26 2014-10-26
27 2014-10-27
28 2014-10-28
29 2014-10-29
30 2014-10-30
31 2014-10-31
I tried to make a temp table which contains every date in the month, and then left join it with the first table I mentioned, but it seemed to not work.
declare #datetemp table (
stmpdate varchar(10)
);
insert into #datetemp
SELECT '2014-10-01'
UNION ALL
SELECT '2014-10-02'
UNION ALL
SELECT '2014-10-03'
....
and
SELECT dtt.stmpdate, intime
FROM #datetemp dtt left join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE (emp_no = '001234567')
here is the result of query above
stmpdate intime
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:59:56
2014-10-17 07:45:56
and here is the result of select * from #datetemp
2014-10-01
2014-10-02
2014-10-03
2014-10-04
2014-10-05
2014-10-06
2014-10-07
2014-10-08
2014-10-09
2014-10-10
2014-10-11
2014-10-12
2014-10-13
2014-10-14
2014-10-15
2014-10-16
2014-10-17
2014-10-18
2014-10-19
2014-10-20
2014-10-21
2014-10-22
2014-10-23
2014-10-24
2014-10-25
2014-10-26
2014-10-27
2014-10-28
2014-10-29
2014-10-30
2014-10-31
you're filtering for only where emp_no has a value. if they didn't check in, it won't return on that row because you just have date info and no employee number. so you have to allow for equal or null.
SELECT dtt.stmpdate, intime
FROM #datetemp dtt
left outer join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE emp_no = '001234567' or emp_no is null
also, for your dates... check this out: http://www.sqlservercurry.com/2010/03/generate-start-and-end-date-range-using.html
DECLARE
#StartDate datetime = '2010-01-01',
#EndDate datetime = '2010-03-01'
;WITH datetemp as
(
SELECT #StartDate as stmpdate
UNION ALL
SELECT DATEADD(day, 1, stmpdate)
FROM datetemp
WHERE DATEADD(day, 1, stmpdate) <= #EndDate
)
SELECT stmpdate
FROM datetemp;
you would then select from datetemp as a normal table. beware, though, a common table expression can only be used once and immediately following the with statement.
just trust me on this one... run this query and see how your blank lines occur:
SELECT dtt.stmpdate, intime, emp_no
FROM #datetemp dtt
left outer join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE emp_no = '001234567' or emp_no is null
all these lines will return with emp_no = 001234567
stmpdate intime
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:59:56
2014-10-17 07:45:56
and all your blank lines will have null as emp_no.
I got my answer!!
SELECT dtt.stmpdate, intime
FROM #datetemp dtt left join
(
SELECT stmpdate, intime
FROM v_dayTimesheet
WHERE (emp_no = '001234567')
) as vdayTimesheet
on sparedate.stmpdate=vdayTimesheet.stampdate
ORDER BY stmpdate
this is what I want, thanks everyone
SQL Query:
SQLFIDDLEExample
SELECT t2.dt,
isnull(t1.intime, '') intime
FROM
(
SELECT DATEADD(day,number,'2014-10-01') dt
FROM master..spt_values
WHERE Type = 'P'
AND DATEADD(day,number,'2014-10-01') >= '2014-10-01'
AND DATEADD(day,number,'2014-10-01') < '2014-11-01'
) t2
LEFT JOIN Table1 t1
ON t1.stmpdate = t2.dt
Result:
| DT | INTIME |
|--------------------------------|----------|
| October, 01 2014 00:00:00+0000 | |
| October, 02 2014 00:00:00+0000 | |
| October, 03 2014 00:00:00+0000 | |
| October, 04 2014 00:00:00+0000 | |
| October, 05 2014 00:00:00+0000 | |
| October, 06 2014 00:00:00+0000 | |
| October, 07 2014 00:00:00+0000 | |
| October, 08 2014 00:00:00+0000 | 08:04:43 |
| October, 09 2014 00:00:00+0000 | 07:57:13 |
| October, 10 2014 00:00:00+0000 | 07:57:14 |
| October, 11 2014 00:00:00+0000 | |
| October, 12 2014 00:00:00+0000 | |
| October, 13 2014 00:00:00+0000 | |
| October, 14 2014 00:00:00+0000 | |
| October, 15 2014 00:00:00+0000 | |
| October, 16 2014 00:00:00+0000 | 07:79:56 |
| October, 17 2014 00:00:00+0000 | 07:45:56 |
| October, 18 2014 00:00:00+0000 | |
| October, 19 2014 00:00:00+0000 | |
| October, 20 2014 00:00:00+0000 | |
| October, 21 2014 00:00:00+0000 | |
| October, 22 2014 00:00:00+0000 | |
| October, 23 2014 00:00:00+0000 | |
| October, 24 2014 00:00:00+0000 | |
| October, 25 2014 00:00:00+0000 | |
| October, 26 2014 00:00:00+0000 | |
| October, 27 2014 00:00:00+0000 | |
| October, 28 2014 00:00:00+0000 | |
| October, 29 2014 00:00:00+0000 | |
| October, 30 2014 00:00:00+0000 | |
| October, 31 2014 00:00:00+0000 | |

MS SQL query to return next start time and pervious end time

I have a table with columns, Machine, job_name, Start_time. Machine and job name are text and Start_time is Date/time.
I would like a query that will return the next chronological start time for a machine as the end time.
I have tried to use a MIN(start_time) > Start time. But this returns a row of Multiple start times for every possible end time. I am not sure how to identify the Start_time per row as the comparision start_time.
Table example.
MAchine, Job_name, Start_time
scanner, A1A, 1/24/2014 8:00am
scanner, ABA, 1/24/2014 12:00pm
scanner, A1B, 1/24/2014 10:00pm
scanner, AC3, 1/25/2014 4:00am
scanner, AG2, 1/25/2014 11:00am
scanner, BK4, 1/25/2014 3:00pm
scanner1, AA, 1/24/2014 9:00am
scanner1, AA, 1/24/2014 1:00pm
scanner1, AB, 1/24/2014 8:00pm
scanner1, A3, 1/25/2014 2:00am
scanner1, A2, 1/25/2014 7:00am
scanner1, B4, 1/25/2014 2:00pm
scanner2, A1, 1/24/2014 11:00am
scanner2, AB, 1/24/2014 12:00pm
scanner2, A1, 1/24/2014 5:00pm
scanner2, AC, 1/25/2014 1:00am
scanner2, A2, 1/25/2014 5:00am
scanner2, K4, 1/25/2014 2:00pm
I would like results below.
MAchine, Job_name, Start_time
scanner, A1A, 1/24/2014 8:00am, 1/24/2014 12:00pm
scanner, ABA, 1/24/2014 12:00pm, 1/24/2014 10:00pm
scanner, A1B, 1/24/2014 10:00pm, 1/25/2014 4:00am
scanner, AC3, 1/25/2014 4:00am, 1/25/2014 11:00am
scanner, AG2, 1/25/2014 11:00am, 1/25/201 3:00pm
scanner, BK4, 1/25/2014 3:00pm,
scanner1, AA, 1/24/2014 9:00am, 1/24/2014 1:00pm
scanner1, AA, 1/24/2014 1:00pm, 1/24/2014 8:00pm
scanner1, AB, 1/24/2014 8:00pm, 1/25/2014 2:00am
scanner1, A3, 1/25/2014 2:00am, 1/25/2014 7:00am
scanner1, A2, 1/25/2014 7:00am, 1/25/2014 2:00pm
scanner1, B4, 1/25/2014 2:00pm,
scanner2, A1, 1/24/2014 11:00am, 1/24/2014 12:00pm
scanner2, AB, 1/24/2014 12:00pm, 1/24/2014 5:00pm
scanner2, A1, 1/24/2014 5:00pm, 1/25/2014 1:00am
scanner2, AC, 1/25/2014 1:00am, 1/25/2014 5:00am
scanner2, A2, 1/25/2014 5:00am, 1/25/2014 2:00pm
scanner2, K4, 1/25/2014 2:00pm,
You will want to consider looking at the LAG and LEAD functions available in SQL Server 2012 and above.
This approach will work with most databases:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Table1
([MAchine] varchar(8), [Job_name] varchar(3), [Start_time] datetime)
;
INSERT INTO Table1
([MAchine], [Job_name], [Start_time])
VALUES
('scanner', 'A1A', '1/24/2014 8:00am'),
('scanner', 'ABA', '1/24/2014 12:00pm'),
('scanner', 'A1B', '1/24/2014 10:00pm'),
('scanner', 'AC3', '1/25/2014 4:00am'),
('scanner', 'AG2', '1/25/2014 11:00am'),
('scanner', 'BK4', '1/25/2014 3:00pm'),
('scanner1', 'AA', '1/24/2014 9:00am'),
('scanner1', 'AA', '1/24/2014 1:00pm'),
('scanner1', 'AB', '1/24/2014 8:00pm'),
('scanner1', 'A3', '1/25/2014 2:00am'),
('scanner1', 'A2', '1/25/2014 7:00am'),
('scanner1', 'B4', '1/25/2014 2:00pm'),
('scanner2', 'A1', '1/24/2014 11:00am'),
('scanner2', 'AB', '1/24/2014 12:00pm'),
('scanner2', 'A1', '1/24/2014 5:00pm'),
('scanner2', 'AC', '1/25/2014 1:00am'),
('scanner2', 'A2', '1/25/2014 5:00am'),
('scanner2', 'K4', '1/25/2014 2:00pm')
;
Query 1:
select t3.MAchine, t3.Job_name, t3.Start_time, tm.MinNextTime
from Table1 t3
left outer join (
select t1.MAchine, t1.Start_time, min(t2.Start_time) as MinNextTime
from Table1 t1
inner join Table1 t2 on t1.MAchine = t2.MAchine and t2.Start_time > t1.Start_time
group by t1.MAchine, t1.Start_time
) tm on t3.MAchine = tm.MAchine and t3.Start_time = tm.Start_time
order by t3.MAchine, t3.Start_time
Results:
| MACHINE | JOB_NAME | START_TIME | MINNEXTTIME |
|----------|----------|--------------------------------|--------------------------------|
| scanner | A1A | January, 24 2014 08:00:00+0000 | January, 24 2014 12:00:00+0000 |
| scanner | ABA | January, 24 2014 12:00:00+0000 | January, 24 2014 22:00:00+0000 |
| scanner | A1B | January, 24 2014 22:00:00+0000 | January, 25 2014 04:00:00+0000 |
| scanner | AC3 | January, 25 2014 04:00:00+0000 | January, 25 2014 11:00:00+0000 |
| scanner | AG2 | January, 25 2014 11:00:00+0000 | January, 25 2014 15:00:00+0000 |
| scanner | BK4 | January, 25 2014 15:00:00+0000 | (null) |
| scanner1 | AA | January, 24 2014 09:00:00+0000 | January, 24 2014 13:00:00+0000 |
| scanner1 | AA | January, 24 2014 13:00:00+0000 | January, 24 2014 20:00:00+0000 |
| scanner1 | AB | January, 24 2014 20:00:00+0000 | January, 25 2014 02:00:00+0000 |
| scanner1 | A3 | January, 25 2014 02:00:00+0000 | January, 25 2014 07:00:00+0000 |
| scanner1 | A2 | January, 25 2014 07:00:00+0000 | January, 25 2014 14:00:00+0000 |
| scanner1 | B4 | January, 25 2014 14:00:00+0000 | (null) |
| scanner2 | A1 | January, 24 2014 11:00:00+0000 | January, 24 2014 12:00:00+0000 |
| scanner2 | AB | January, 24 2014 12:00:00+0000 | January, 24 2014 17:00:00+0000 |
| scanner2 | A1 | January, 24 2014 17:00:00+0000 | January, 25 2014 01:00:00+0000 |
| scanner2 | AC | January, 25 2014 01:00:00+0000 | January, 25 2014 05:00:00+0000 |
| scanner2 | A2 | January, 25 2014 05:00:00+0000 | January, 25 2014 14:00:00+0000 |
| scanner2 | K4 | January, 25 2014 14:00:00+0000 | (null) |