Oracle SQL get last year of dates excluding weekends - sql

I'd expect this to work to get me a list of calendar dates over the past 12 months excluding weekends; but it just gives me the entire list of dates - which I suppose is fine - but want to know why the below is incorrect.
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum AS CalendarDate
FROM all_objects
WHERE ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum <= sysdate
AND to_char(sysdate,'DY') NOT IN ('SAT','SUN')

Because you're doing this:
AND to_char(sysdate,'DY') NOT IN ('SAT','SUN')
And today isn't Saturday or Sunday. You need to look at the calculated CalendarDate value; but you can't do that in the same level of subquery. You could try to recalculate it:
AND to_char(ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum,'DY') NOT IN ('SAT','SUN')
but this will return no rows - at least when run at the moment. As it happens, March 1st 2020 was a Sunday, so that is excluded; and because of when and how rownum is generated, that result is excluded, and the next one sees the same value, which is excluded, and so on.
You can use an inline view to avoid both issues:
SELECT CalendarDate
FROM (
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum AS CalendarDate
FROM all_objects
WHERE ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum <= sysdate
)
WHERE to_char(CalendarDate,'DY','NLS_DATE_LANGUAGE=ENGLISH') NOT IN ('SAT','SUN')
CALENDARDATE
02-MAR-20
03-MAR-20
04-MAR-20
05-MAR-20
06-MAR-20
09-MAR-20
10-MAR-20
...
db<>fiddle
I've chucked in a language modifier to stop it behaving differently for users with sessions not set to English.
Querying against all_objects isn't ideal though, it would be better to use a hierarcical query:
SELECT *
FROM (
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + level AS CalendarDate
FROM dual
CONNECT BY level <= TRUNC(SYSDATE) - ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) + 1
)
WHERE to_char(CalendarDate,'DY','NLS_DATE_LANGUAGE=ENGLISH') NOT IN ('SAT','SUN')
ORDER BY CalendarDate
db<>fiddle
or a recursive CTE, if you're 11gR2+:
WITH rcte (CalendarDate) AS (
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12)
FROM dual
UNION ALL
SELECT rcte.CalendarDate + interval '1' day
FROM rcte
WHERE rcte.CalendarDate < TRUNC(SYSDATE)
)
SELECT CalendarDate
FROM rcte
WHERE to_char(CalendarDate,'DY','NLS_DATE_LANGUAGE=ENGLISH') NOT IN ('SAT','SUN')
ORDER BY CalendarDate
db<>fiddle (as 18c to avoid a couple of issues with the patch level in the 11g version it uses).

You checking whether today is sunday or monday with to_char(sysdate,'DY'). you need to check CalendarDate which is not available in your window. You can use cte to calculate the calendar then you can remove weekends with your condition as below.
with cte (CalendarDate) as
(
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum AS CalendarDate
FROM all_objects
WHERE ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum <= sysdate
)
select * from cte where
to_char(CalendarDate,'DY') not in ('SAT','SUN');
| CALENDARDATE |
| :----------- |
| 02-MAR-20 |
| 03-MAR-20 |
| 04-MAR-20 |
| 05-MAR-20 |
| 06-MAR-20 |
| 09-MAR-20 |
| 10-MAR-20 |
| 11-MAR-20 |
| 12-MAR-20 |
| 13-MAR-20 |
| 16-MAR-20 |
| 17-MAR-20 |
| 18-MAR-20 |
| 19-MAR-20 |
| 20-MAR-20 |
| 23-MAR-20 |
| 24-MAR-20 |
| 25-MAR-20 |
| 26-MAR-20 |
| 27-MAR-20 |
| 30-MAR-20 |
| 31-MAR-20 |
| 01-APR-20 |
| 02-APR-20 |
| 03-APR-20 |
| 06-APR-20 |
| 07-APR-20 |
| 08-APR-20 |
| 09-APR-20 |
| 10-APR-20 |
| 13-APR-20 |
| 14-APR-20 |
| 15-APR-20 |
| 16-APR-20 |
| 17-APR-20 |
| 20-APR-20 |
| 21-APR-20 |
| 22-APR-20 |
| 23-APR-20 |
| 24-APR-20 |
| 27-APR-20 |
| 28-APR-20 |
| 29-APR-20 |
| 30-APR-20 |
| 01-MAY-20 |
| 04-MAY-20 |
| 05-MAY-20 |
| 06-MAY-20 |
| 07-MAY-20 |
| 08-MAY-20 |
| 11-MAY-20 |
| 12-MAY-20 |
| 13-MAY-20 |
| 14-MAY-20 |
| 15-MAY-20 |
| 18-MAY-20 |
| 19-MAY-20 |
| 20-MAY-20 |
| 21-MAY-20 |
| 22-MAY-20 |
| 25-MAY-20 |
| 26-MAY-20 |
| 27-MAY-20 |
| 28-MAY-20 |
| 29-MAY-20 |
| 01-JUN-20 |
| 02-JUN-20 |
| 03-JUN-20 |
| 04-JUN-20 |
| 05-JUN-20 |
| 08-JUN-20 |
| 09-JUN-20 |
| 10-JUN-20 |
| 11-JUN-20 |
| 12-JUN-20 |
| 15-JUN-20 |
| 16-JUN-20 |
| 17-JUN-20 |
| 18-JUN-20 |
| 19-JUN-20 |
| 22-JUN-20 |
| 23-JUN-20 |
| 24-JUN-20 |
| 25-JUN-20 |
| 26-JUN-20 |
| 29-JUN-20 |
| 30-JUN-20 |
| 01-JUL-20 |
| 02-JUL-20 |
| 03-JUL-20 |
| 06-JUL-20 |
| 07-JUL-20 |
| 08-JUL-20 |
| 09-JUL-20 |
| 10-JUL-20 |
| 13-JUL-20 |
| 14-JUL-20 |
| 15-JUL-20 |
| 16-JUL-20 |
| 17-JUL-20 |
| 20-JUL-20 |
| 21-JUL-20 |
| 22-JUL-20 |
| 23-JUL-20 |
| 24-JUL-20 |
| 27-JUL-20 |
| 28-JUL-20 |
| 29-JUL-20 |
| 30-JUL-20 |
| 31-JUL-20 |
| 03-AUG-20 |
| 04-AUG-20 |
| 05-AUG-20 |
| 06-AUG-20 |
| 07-AUG-20 |
| 10-AUG-20 |
| 11-AUG-20 |
| 12-AUG-20 |
| 13-AUG-20 |
| 14-AUG-20 |
| 17-AUG-20 |
| 18-AUG-20 |
| 19-AUG-20 |
| 20-AUG-20 |
| 21-AUG-20 |
| 24-AUG-20 |
| 25-AUG-20 |
| 26-AUG-20 |
| 27-AUG-20 |
| 28-AUG-20 |
| 31-AUG-20 |
| 01-SEP-20 |
| 02-SEP-20 |
| 03-SEP-20 |
| 04-SEP-20 |
| 07-SEP-20 |
| 08-SEP-20 |
| 09-SEP-20 |
| 10-SEP-20 |
| 11-SEP-20 |
| 14-SEP-20 |
| 15-SEP-20 |
| 16-SEP-20 |
| 17-SEP-20 |
| 18-SEP-20 |
| 21-SEP-20 |
| 22-SEP-20 |
| 23-SEP-20 |
| 24-SEP-20 |
| 25-SEP-20 |
| 28-SEP-20 |
| 29-SEP-20 |
| 30-SEP-20 |
| 01-OCT-20 |
| 02-OCT-20 |
| 05-OCT-20 |
| 06-OCT-20 |
| 07-OCT-20 |
| 08-OCT-20 |
| 09-OCT-20 |
| 12-OCT-20 |
| 13-OCT-20 |
| 14-OCT-20 |
| 15-OCT-20 |
| 16-OCT-20 |
| 19-OCT-20 |
| 20-OCT-20 |
| 21-OCT-20 |
| 22-OCT-20 |
| 23-OCT-20 |
| 26-OCT-20 |
| 27-OCT-20 |
| 28-OCT-20 |
| 29-OCT-20 |
| 30-OCT-20 |
| 02-NOV-20 |
| 03-NOV-20 |
| 04-NOV-20 |
| 05-NOV-20 |
| 06-NOV-20 |
| 09-NOV-20 |
| 10-NOV-20 |
| 11-NOV-20 |
| 12-NOV-20 |
| 13-NOV-20 |
| 16-NOV-20 |
| 17-NOV-20 |
| 18-NOV-20 |
| 19-NOV-20 |
| 20-NOV-20 |
| 23-NOV-20 |
| 24-NOV-20 |
| 25-NOV-20 |
| 26-NOV-20 |
| 27-NOV-20 |
| 30-NOV-20 |
| 01-DEC-20 |
| 02-DEC-20 |
| 03-DEC-20 |
| 04-DEC-20 |
| 07-DEC-20 |
| 08-DEC-20 |
| 09-DEC-20 |
| 10-DEC-20 |
| 11-DEC-20 |
| 14-DEC-20 |
| 15-DEC-20 |
| 16-DEC-20 |
| 17-DEC-20 |
| 18-DEC-20 |
| 21-DEC-20 |
| 22-DEC-20 |
| 23-DEC-20 |
| 24-DEC-20 |
| 25-DEC-20 |
| 28-DEC-20 |
| 29-DEC-20 |
| 30-DEC-20 |
| 31-DEC-20 |
| 01-JAN-21 |
| 04-JAN-21 |
| 05-JAN-21 |
| 06-JAN-21 |
| 07-JAN-21 |
| 08-JAN-21 |
| 11-JAN-21 |
| 12-JAN-21 |
| 13-JAN-21 |
| 14-JAN-21 |
| 15-JAN-21 |
| 18-JAN-21 |
| 19-JAN-21 |
| 20-JAN-21 |
| 21-JAN-21 |
| 22-JAN-21 |
| 25-JAN-21 |
| 26-JAN-21 |
| 27-JAN-21 |
| 28-JAN-21 |
| 29-JAN-21 |
| 01-FEB-21 |
| 02-FEB-21 |
| 03-FEB-21 |
| 04-FEB-21 |
| 05-FEB-21 |
| 08-FEB-21 |
| 09-FEB-21 |
| 10-FEB-21 |
| 11-FEB-21 |
| 12-FEB-21 |
| 15-FEB-21 |
| 16-FEB-21 |
| 17-FEB-21 |
| 18-FEB-21 |
| 19-FEB-21 |
| 22-FEB-21 |
| 23-FEB-21 |
| 24-FEB-21 |
| 25-FEB-21 |
| 26-FEB-21 |
| 01-MAR-21 |
| 02-MAR-21 |
| 03-MAR-21 |
| 04-MAR-21 |
| 05-MAR-21 |
| 08-MAR-21 |
| 09-MAR-21 |
db<>fiddle here

Related

How can I only "pick" (not aggregated) one row if there are duplicate values on specific column? [duplicate]

This question already has answers here:
Select first row in each GROUP BY group?
(20 answers)
Closed 2 years ago.
Right now I have this query:
SELECT DISTINCT
stock_picking.id as delivery_order_id,
sale_order.id as sale_order_id,
sale_order.name as sale_order_name,
stock_picking.origin as stock_picking_origin,
stock_picking.name as stock_picking_name,
stock_picking.create_date as stock_picking_create_date,
sub.count_origin as sale_order_delivery_order_done_count
FROM
(
SELECT
origin,
COUNT(origin) as count_origin
FROM stock_picking
WHERE state = 'done'
GROUP BY origin
HAVING COUNT(origin) > 1
ORDER BY origin
) sub
JOIN sale_order ON sale_order.name = sub.origin
JOIN account_invoice ON account_invoice.origin = sale_order.name
JOIN stock_picking ON stock_picking.origin = sale_order.name
WHERE
account_invoice.create_date >= '04/17/20' AND
sale_order.create_date <= '04/01/20 07:00' AND
sale_order.create_date >= '03/01/20'
ORDER BY sale_order.name
;
It returns:
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
| delivery_order_id | sale_order_id | sale_order_name | stock_picking_origin | stock_picking_name | stock_picking_create_date | sale_order_delivery_order_done_count |
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
| 2053131 | 5840046 | 3258428 | 3258428 | WH/OUT/1804215 | 2020-03-01 07:10:32.144694 | 2 |
| 2071149 | 5840046 | 3258428 | 3258428 | WH/OUT/1819605 | 2020-03-03 18:00:25.208632 | 2 |
| 2154480 | 5840046 | 3258428 | 3258428 | WH/OUT/1894584 | 2020-03-11 08:39:33.514114 | 2 |
| 2053494 | 5840408 | 3258728 | 3258728 | WH/OUT/1804574 | 2020-03-01 07:41:26.728154 | 2 |
| 2105133 | 5840408 | 3258728 | 3258728 | WH/OUT/1849288 | 2020-03-07 13:59:10.049683 | 2 |
| 2192492 | 5840408 | 3258728 | 3258728 | WH/OUT/1929553 | 2020-03-13 09:10:26.18469 | 2 |
| 2061022 | 5861189 | 3279458 | 3279458 | WH/OUT/1811084 | 2020-03-02 14:37:35.803326 | 2 |
| 2170656 | 5861189 | 3279458 | 3279458 | WH/OUT/1909477 | 2020-03-12 08:57:15.434752 | 2 |
| 2072002 | 5885577 | 3294059 | 3294059 | WH/OUT/109633 | 2020-03-04 02:44:03.302924 | 2 |
| 2130430 | 5885577 | 3294059 | 3294059 | WH/OUT/114259 | 2020-03-10 03:13:58.33838 | 2 |
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
I want to make sure that the column sale_order_id is unique, but picked from the least delivery_order_id and not aggregated.
I want to have a result like this:
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
| delivery_order_id | sale_order_id | sale_order_name | stock_picking_origin | stock_picking_name | stock_picking_create_date | sale_order_delivery_order_done_count |
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
| 2053131 | 5840046 | 3258428 | 3258428 | WH/OUT/1804215 | 2020-03-01 07:10:32.144694 | 2 |
| 2053494 | 5840408 | 3258728 | 3258728 | WH/OUT/1804574 | 2020-03-01 07:41:26.728154 | 2 |
| 2061022 | 5861189 | 3279458 | 3279458 | WH/OUT/1811084 | 2020-03-02 14:37:35.803326 | 2 |
| 2072002 | 5885577 | 3294059 | 3294059 | WH/OUT/109633 | 2020-03-04 02:44:03.302924 | 2 |
+-------------------+---------------+-----------------+----------------------+--------------------+----------------------------+--------------------------------------+
You can use distinct on. Your query is complicated, so I'll encapsulate it in a CTE:
with q as (
. . .
)
select distinct on (sale_order_id) q.*
from q
order by sale_order_id, delivery_order_id;

Crosstab query to show the working hours per day for each Vessel

I have made a Crosstab Query that should give information about the total working hours in each day for every Vessel we had in our small harbor.
my query:
TRANSFORM Sum(Main.WorkingH) AS SumOfWorkingH
SELECT DateValue([DeptDate]) AS [Date]
FROM Vessels INNER JOIN Main ON Vessels.ID = Main.VesselID
GROUP BY DateValue([DeptDate])
ORDER BY DateValue([DeptDate])
PIVOT Vessels.Vessel;
the problem here is this query is returning the total working hours start from departure date
| +---------------+--------+----+----+----+----+----+----+ |
| | | | | | | | | | |
| +---------------+--------+----+----+----+----+----+----+ |
| | Date | A1 | A2 | A3 | F3 | F4 | F5 | F6 | |
| | 26-May-17 | | | 32 | 29 | | | | |
| | 27-May-17 | 3 | 13 | | | | | | |
| | 28-May-17 | | | | | | | 73 | |
| | 29-May-17 | | | | 12 | 6 | 27 | | |
| | 01-Jun-17 | | | 10 | | 7 | 41 | | |
| | 02-Jun-17 | | 2 | 15 | 5 | | | | |
| | 03-Jun-17 | | 4 | | | | | | |
| +---------------+--------+----+----+----+----+----+----+ |
The desired Result
when a vessel leaves at 6/1 9pm and arrive back at 6/3 10am. This should appear as following:
6/1-->3Hours
6/2-->24Hours
6/3-->10Hours
**NOT** 6/1-->37Hours as in the previous table.
This is how it should look like
| +----------------+-----+----+----+----+--------+----+----+ |
| | Date | A1 | A2 | A3 | F3 | F4 | F5 | F6 | |
| +----------------+-----+----+----+----+--------+----+----+ |
| | 26-May-17 | | | 5 | 7 | | | | |
| | 27-May-17 | 3 | 13 | 24 | 21 | | | | |
| | 28-May-17 | | | 2 | | | | 9 | |
| | 29-May-17 | | | | 12 | 6 | 8 | 24 | |
| | 30-May-17 | | | | | | 18 | 24 | |
| | 31-May-17 | | | | | | | 15 | |
| | 01-Jun-17 | | | 10 | | 7 | 0 | | |
| | 02-Jun-17 | | 2 | 15 | 5 | 24 | | | |
| | 03-Jun-17 | | 4 | | | | 16 | | |
| +----------------+-----+----+----+----+--------+----+----+ |
These values are not accurate (I wrote them by hand), but I think you got the Idea
The Suggested Solution
while trying to fix this problem I made the following code which takes the
Public Function HoursByDate1(stTime, EndTime)
For dayloop = Int(EndTime) To Int(stTime) Step -1
If dayloop = Int(stTime) Then
WorkingHours = Hour(dayloop + 1 - stTime)
ElseIf dayloop = Int(EndTime) Then
WorkingHours = Hour(EndTime - dayloop)
Else
WorkingHours = 24
End If
HoursByDate1 = WorkingHours
Debug.Print "StartDate: " & stTime & ", EndDate:" & EndTime & ", The day:" & dayloop & " --> " & WorkingHours & " hours."
Next dayloop
End Function
It prints the data as following:
which is exactly what I want
But when I try to call this function from my query, It gets only the last value for each trip. as following:
| +-----------+----+----+----+----+----+----+----+ |
| | Date | A1 | A2 | A3 | F3 | F4 | F5 | F6 | |
| +-----------+----+----+----+----+----+----+----+ |
| | 5/26/2017 | | | 5 | 7 | | | | |
| | 5/27/2017 | 15 | 19 | | | | | | |
| | 5/28/2017 | | | | | | | 9 | |
| | 5/29/2017 | | | | 8 | 7 | 8 | | |
| | 6/1/2017 | | | 3 | | 6 | 0 | | |
| | 6/2/2017 | | 8 | 8 | 19 | | | | |
| | 6/3/2017 | | 9 | | | | | |
I seek any Solution: From VBA side of things or SQL Query Side.
Sorry for the very long question, but I wanted to show my effort on the subject because every time I am told that this is not enough Information

Fill in data from another table using ranges in postgresql

I'm filling empty arrivals time in a bus timetable, I have start,end and some midpoints times, I do by calculating average speed between start and end route, but results are inexact, so must use intervals speed to compute arrivals times.
General Timetable shown in First Code Snippet, please run to see table, and Computed arrival times for Intervals in Second Code Snippet .
What I'm trying to do is to fill in av_speed ingeneral timetable with Intervals average speed, i.e. put 251.17 into timetable stops_sequences 1 to 5, 230.68 into sequences 6 to 10 and so on.
+============+===============+==============+==========+===========+===========+==========+
| stoptimeid | stop_sequence | arrival_time | distance | dist_trav | time_trav | av_speed |
+============+===============+==============+==========+===========+===========+==========+
| 54689 | 1 | 6:05:00 | 0,00 | | | 220,98 |
| 54690 | 2 | | 0,35 | | | 220,98 |
| 54691 | 3 | | 0,49 | | | 220,98 |
| 54692 | 4 | | 0,91 | | | 220,98 |
| 54693 | 5 | 6:10:00 | 1,19 | | | 220,98 |
| 54694 | 6 | | 1,50 | | | 220,98 |
| 54695 | 7 | | 1,67 | | | 220,98 |
| 54696 | 8 | | 1,96 | | | 220,98 |
| 54697 | 9 | | 2,16 | | | 220,98 |
| 54698 | 10 | 6:15:00 | 2,49 | | | 220,98 |
| 54699 | 11 | | 2,64 | | | 220,98 |
| 54700 | 12 | | 3,11 | | | 220,98 |
| 54701 | 13 | | 3,79 | | | 220,98 |
| 54702 | 14 | | 4,14 | | | 220,98 |
| 54703 | 15 | | 4,39 | | | 220,98 |
| 54704 | 16 | | 4,96 | | | 220,98 |
| 54705 | 17 | | 5,10 | | | 220,98 |
| 54706 | 18 | 6:25:00 | 5,21 | | | 220,98 |
+============+===============+==============+==========+===========+===========+==========+
+============+===============+==============+==========+===========+===========+==========+
| stoptimeid | stop_sequence | arrival_time | distance | dist_trav | time_trav | av_speed |
+============+===============+==============+==========+===========+===========+==========+
| 54689 | 1 | 6:05:00 | 0,00 | | | |
| 54693 | 5 | 6:10:00 | 1,19 | 1,194423 | 300 | 251,17 |
| 54698 | 10 | 6:15:00 | 2,49 | 1,300520 | 300 | 230,68 |
| 54706 | 18 | 6:25:00 | 5,21 | 2,715214 | 600 | 220,98 |
+============+===============+==============+==========+===========+===========+==========+
Have checked the use of a CASE function that fills in descending order, fills 18 to 1, then fills 10 to 5 and finally 5 to 1, so final result it's ok.
This is what I tried but only fill with only one av_speed, the last one.
CREATE OR REPLACE VIEW arrivaltime_check AS
SELECT
CASE
WHEN arrivaltime.stop_sequence<=foo.stop_sequence THEN foo.av_speed
ELSE foo.av_speed END,foo.trip_id2,foo.stop_sequence
FROM
public.arrivaltime,
(SELECT
b.rid,
b.trip_id2,
b.stoptimeid,
b.stop_sequence,
b.arrival_time,
extract(epoch from (b.arrival_time)) as time_epoch,
b.distance,
b.distance -lag(b.distance,1) over (partition by b.trip_id2 ) as dist_trav,
b.time_epoch -lag(b.time_epoch,1) over (partition by b.trip_id2 ) as time_trav,
(b.time_epoch -lag(b.time_epoch,1) over (partition by b.trip_id2 ))/(b.distance -lag(b.distance,1) over (partition by b.trip_id2 )) as av_speed
from public.timecalc1 b
order by b.trip_id2,b.stop_sequence desc) foo;
foo subquery only computes values when arrivaltimes is not null,
How can I fill in timetable with intervals av_speed?

Considering values from one table as column header in another

I have a base table where I need to calculate the difference between two dates based on the type of the entry.
tblA
+----------+------------+---------------+--------------+
| TypeCode | Log_Date | Complete_Date | Pending_Date |
+----------+------------+---------------+--------------+
| 1 | 18/04/2016 | 19/04/2016 | |
| 2 | 10/04/2016 | 18/04/2016 | 15/04/2016 |
| 3 | 12/04/2016 | 19/04/2016 | |
| 4 | 15/04/2016 | 17/04/2016 | 16/04/2016 |
| 5 | 16/04/2016 | 21/04/2016 | |
| 1 | 19/04/2016 | 20/04/2016 | |
| 2 | 20/03/2016 | 31/03/2015 | |
| 3 | 25/03/2016 | 28/03/2016 | |
| 4 | 26/03/2016 | 27/03/2016 | |
| 5 | 27/03/2016 | 30/03/2016 | |
+----------+------------+---------------+--------------+
I have another look up table which has the column names to be considered based on the TypeCode.
tblB
+----------+----------+---------------+
| TypeCode | DateCol1 | DateCol2 |
+----------+----------+---------------+
| 1 | Log_Date | Complete_Date |
| 2 | Log_Date | Pending_Date |
| 3 | Log_Date | Complete_Date |
| 4 | Log_Date | Pending_Date |
| 5 | Log_Date | Complete_Date |
+----------+----------+---------------+
I am doing a simple DATEDIFF between two dates for my calculation. However I want to lookup which columns to consider for this calculation from tblB and apply it on tblA based on the TypeCode.
Resulting table:
For example: When the TypeCode is 2 or 4 then the calculation should be DATEDIFF(d, Log_Date, Pending_Date), otherwise DATEDIFF(d, Log_Date, Complete_Date)
+----------+------------+---------------+--------------+----------+
| TypeCode | Log_Date | Complete_Date | Pending_Date | Cal_Days |
+----------+------------+---------------+--------------+----------+
| 1 | 18/04/2016 | 19/04/2016 | | 1 |
| 2 | 10/04/2016 | 18/04/2016 | 15/04/2016 | 5 |
| 3 | 12/04/2016 | 19/04/2016 | | 7 |
| 4 | 15/04/2016 | 17/04/2016 | 16/04/2016 | 1 |
| 5 | 16/04/2016 | 21/04/2016 | | 5 |
| 1 | 19/04/2016 | 20/04/2016 | | 1 |
| 2 | 20/03/2016 | 31/03/2015 | | |
| 3 | 25/03/2016 | 28/03/2016 | | 3 |
| 4 | 26/03/2016 | 27/03/2016 | | |
| 5 | 27/03/2016 | 30/03/2016 | | 3 |
+----------+------------+---------------+--------------+----------+
Any help would be appreciated. Thanks.
Use JOIN with CASE expression:
SELECT
a.*,
Cal_Days =
DATEDIFF(
DAY,
CASE
WHEN b.DateCol1 = 'Log_Date' THEN a.Log_Date
WHEN b.DateCol1 = 'Complete_Date' THEN a.Complete_Date
ELSE a.Pending_Date
END,
CASE
WHEN b.DateCol2 = 'Log_Date' THEN a.Log_Date
WHEN b.DateCol2 = 'Complete_Date' THEN a.Complete_Date
ELSE a.Pending_Date
END
)
FROM TblA a
INNER JOIN TblB b
ON b.TypeCode = a.TypeCode

Running total SQL server - AGAIN

i'm aware that this question has been asked multiple times and I have read those threads to get to where I am now, but those solutions don't seem to be working. I need to have a running total of my ExpectedAmount...
I have the following table:
+--------------+----------------+
| ExpectedDate | ExpectedAmount |
+--------------+----------------+
| 1 | 2485513 |
| 2 | 526032 |
| 3 | 342041 |
| 4 | 195807 |
| 5 | 380477 |
| 6 | 102233 |
| 7 | 539951 |
| 8 | 107145 |
| 10 | 165110 |
| 11 | 18795 |
| 12 | 27177 |
| 13 | 28232 |
| 14 | 154631 |
| 15 | 5566585 |
| 16 | 250814 |
| 17 | 90444 |
| 18 | 105424 |
| 19 | 62132 |
| 20 | 1799349 |
| 21 | 303131 |
| 22 | 459464 |
| 23 | 723488 |
| 24 | 676514 |
| 25 | 17311911 |
| 26 | 4876062 |
| 27 | 4844434 |
| 28 | 4039687 |
| 29 | 1418648 |
| 30 | 4366189 |
| 31 | 9028836 |
+--------------+----------------+
I have the following SQL:
SELECT a.ExpectedDate, a.ExpectedAmount, (SELECT SUM(b.ExpectedAmount)
FROM UnpaidManagement..Expected b
WHERE b.ExpectedDate <= a.ExpectedDate)
FROM UnpaidManagement..Expected a
The result of the above SQL is this:
+--------------+----------------+--------------+
| ExpectedDate | ExpectedAmount | RunningTotal |
+--------------+----------------+--------------+
| 1 | 2485513 | 2485513 |
| 2 | 526032 | 9480889 |
| 3 | 342041 | 46275618 |
| 4 | 195807 | 59866450 |
| 5 | 380477 | 60246927 |
| 6 | 102233 | 60349160 |
| 7 | 539951 | 60889111 |
| 8 | 107145 | 60996256 |
| 10 | 165110 | 2650623 |
| 11 | 18795 | 2669418 |
| 12 | 27177 | 2696595 |
| 13 | 28232 | 2724827 |
| 14 | 154631 | 2879458 |
| 15 | 5566585 | 8446043 |
| 16 | 250814 | 8696857 |
| 17 | 90444 | 8787301 |
| 18 | 105424 | 8892725 |
| 19 | 62132 | 8954857 |
| 20 | 1799349 | 11280238 |
| 21 | 303131 | 11583369 |
| 22 | 459464 | 12042833 |
| 23 | 723488 | 12766321 |
| 24 | 676514 | 13442835 |
| 25 | 17311911 | 30754746 |
| 26 | 4876062 | 35630808 |
| 27 | 4844434 | 40475242 |
| 28 | 4039687 | 44514929 |
| 29 | 1418648 | 45933577 |
| 30 | 4366189 | 50641807 |
| 31 | 9028836 | 59670643 |
+--------------+----------------+--------------+
You can tell from the first few values already that the math is all off, but then at some points the math adds up?! I'm Too confused !! Could someone please point me to another solution or to where I have gone wrong with this?
I am using SQL Server 2008.
It is because your ExpectedDate column of type varchar. Try this:
SELECT a.ExpectedDate, a.ExpectedAmount, (SELECT SUM(b.ExpectedAmount)
FROM UnpaidManagement..Expected b
WHERE CAST(b.ExpectedDate as int) <= CAST(a.ExpectedDate as int))
FROM UnpaidManagement..Expected a
Note that it could be inefficient query.
I think this gonna work:
SELECT a.ExpectedDate,
a.ExpectedAmount,
SUM(b.ExpectedAmount) RuningTotal
FROM UnpaidManagement..Expected a
LEFT JOIN UnpaidManagement..Expected b
ON CAST(b.ExpectedDate as int) <= CAST(a.ExpectedDate as int)
GROUP BY a.ExpectedDate, a.ExpectedAmount
AND:
SELECT a.ExpectedDate,
a.ExpectedAmount,
c.RuningTotal
FROM UnpaidManagement..Expected a
CROSS APPLY (
SELECT SUM(b.ExpectedAmount) AS RuningTotal
FROM UnpaidManagement..Expected b
WHERE CAST(b.ExpectedDate as int) <= CAST(a.ExpectedDate as int)
) c