Query in oracle - sql

SELECT PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name
, SUM(Total)
FROM(
(
SELECT PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name
, (SUM(mon) + SUM(tue) + SUM(wed) + SUM(thu) + SUM(fri) + SUM(sat) + SUM(
sun)) Total
FROM tr_view_masterlogentry
WHERE USER_ID = 654321
AND work_year = 2010
GROUP BY PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name
, mon
, tue
, wed
, thu
, fri
, sat
, sun
)
UNION
(
SELECT PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name
, Tot_Amt Total
FROM tr_view_Exchange_loghours
WHERE USER_ID = 654321
AND TO_CHAR(adj_Date, 'yyyy') = 2010
GROUP BY PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name
, Tot_Amt
)
)
GROUP BY PRJ_CC_id
, PROJECT_COSTCENTER_NAME
, AREA_ID
, AREA_Name
, Activity_ID
, Activity_Name;
In this query when i execute it, it will make total of column 'Total' in sum function when values of both 'Total'column in union query is different like 31 and -2 and sum is 29
but when value of both 'Total' column in union query is same like 31 and 31 then it will show only 31 in sum

UNION should be UNION ALL. UNION will remove duplicates.

Related

SQL Query to fetch the most old start_date if there is no change in one column value

I have a table with the following columns per_all_assignments_m-
per_assignments
Person_id position_id system_person_type start_date END_DT
1 1 EMP 01-JAN-2019 20-JAN-2019
1 1 EMP 21-JAN-2019 31-DEC-4712
2 1 EMP 01-JAN-2019 03-JUL-2019
2 1 EMP 04-JUL-2019 08-SEP-2019
2 2 EMP 09-SEP-2019 31-DEC-2019
2 2 EMP 01-JAN-2020 31-DEC-4712
3 10 EMP 01-JAN-2019 20-JAN-2019
3 10 EMP 21-JAN-2019 08-SEP-2019
3 10 EMP 09-SEP-2019 20-JAN-2020
3 10 EMP 21-JAN-2020 31-DEC-4712
I have created the below query to fetch, if there is any value change in the column position_id. This query will fetch the date when the date was changed and the previous start date.
select person_id, prev_start_dt, effective_start_date current_start_dt,
case pos_new when pos_old then 1 else pos_old end pos_old
from (
select person_id, position_id pos_new, effective_start_date, effective_end_date,
lag(position_id) over (partition by person_id order by effective_start_date) pos_old,
lag(effective_start_date) over (partition by person_id order by effective_start_date) prev_start_dt,
case effective_start_date when 1 + lag(effective_end_date) over (partition by person_id order by effective_start_date)
then 1 end flag
from per_all_assignments_m
where person_id=1
and assignment_type = 'E')
where flag = 1 and (pos_new <> pos_old )
For the above table, this query will fetch 09-SEP-2019 for employee #2 as the current_start_dt and 04-JUL-2019 as prev_start_dt
Question-
Now, I want to add the condition where, if there is no change in the position_id values then the most old effective_start_date should be retrieved.
Example-
for EE#1 , current_start_dt should be 01-JAN-2019 and prev_start_dt should be the same for EE#3 , current_start_dt AND prev_start_dt should be
01-JAN-2019.
Any suggestions would be of great help!
Required output -
Person_id prev_start_dt current_start_dt pos_old
1 01-JAN-2019 01-JAN-2019 1
2 04-JUL-2019 09-SEP-2019 1
3 01-JAN-2019 01-JAN-2019 10
Here is one way to do it:
cte2 getr the person_id with changes, and the result is the person_id row and add the first occurence of person_id without changes
Fiddle
with cte as
(
select 1 as Person_id, 1 as position_id, 'EMP' as system_person_type, STR_TO_DATE('01-JAN-2019', "%d-%M-%Y") as start_date, STR_TO_DATE('20-JAN-2019', "%d-%M-%Y") as END_DT
union select 1, 1 , 'EMP' , STR_TO_DATE('21-JAN-2019', "%d-%M-%Y"), STR_TO_DATE('31-DEC-4712', "%d-%M-%Y")
union select 2 , 1 , 'EMP' , STR_TO_DATE('01-JAN-2019', "%d-%M-%Y") , STR_TO_DATE('03-JUL-2019', "%d-%M-%Y")
union select 2 , 1 , 'EMP' , STR_TO_DATE('04-JUL-2019', "%d-%M-%Y") , STR_TO_DATE('08-SEP-2019', "%d-%M-%Y")
union select 2 , 2 , 'EMP' , STR_TO_DATE('09-SEP-2019', "%d-%M-%Y") , STR_TO_DATE('31-DEC-2019' , "%d-%M-%Y")
union select 2 , 2 , 'EMP' , STR_TO_DATE('01-JAN-2020', "%d-%M-%Y") , STR_TO_DATE('31-DEC-4712', "%d-%M-%Y")
union select 3 , 10 , 'EMP' , STR_TO_DATE('01-JAN-2019', "%d-%M-%Y") , STR_TO_DATE('20-JAN-2019' , "%d-%M-%Y")
union select 3 , 10 , 'EMP' , STR_TO_DATE('21-JAN-2019', "%d-%M-%Y") , STR_TO_DATE('08-SEP-2019', "%d-%M-%Y")
union select 3 , 10 , 'EMP' , STR_TO_DATE('09-SEP-2019', "%d-%M-%Y") , STR_TO_DATE('20-JAN-2020', "%d-%M-%Y")
union select 3 , 10 , 'EMP' , STR_TO_DATE('21-JAN-2020', "%d-%M-%Y") ,STR_TO_DATE('31-DEC-4712', "%d-%M-%Y");
),
cte2 as
(
select a.Person_id, ( (b.start_date)) as prev_start_dt, (a.start_date) as current_start_dt, (b.position_id)
from cte a left join cte b on a.Person_id = b.Person_id and a.start_date > b.start_date and a.position_id <> b.position_id
and not exists(select 1 from cte c where a.Person_id = c.Person_id and a.start_date > c.start_date and c.start_date > b.start_date)
)
select Person_id, prev_start_dt, current_start_dt, position_id from cte2 where position_id is not null
union
select a.Person_id, a.start_date, a.start_date, a.position_id from cte a where not exists(select 1 from cte b where a.Person_id = b.Person_id and a.start_date > b.start_date)
and a.Person_id not in (select Person_id from cte2 where position_id is not null)
Output:
Person_id prev_start_dt current_start_dt position_id
1 2019-01-01 2019-01-01 1
2 2019-07-04 2019-09-09 1
3 2019-01-01 2019-01-01 10
If you want to track all the cases where there is a change in Position ID, something like below should work:
with cte as
(
select 1 as Person_id,1 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('20Jan2019' as date) as end_dt from dual union
select 1 as Person_id,1 as position_id,'EMP' as system_person_type,cast('21Jan2019' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual union
select 2 as Person_id,1 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('03Jul2019' as date) as end_dt from dual union
select 2 as Person_id,1 as position_id,'EMP' as system_person_type,cast('04Jul2019' as date) as Start_date,cast('08Sep2019' as date) as end_dt from dual union
select 2 as Person_id,2 as position_id,'EMP' as system_person_type,cast('09Sep2019' as date) as Start_date,cast('31Dec2019' as date) as end_dt from dual union
select 2 as Person_id,2 as position_id,'EMP' as system_person_type,cast('01Jan2020' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual union
select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('20Jan2019' as date) as end_dt from dual union
select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('21Jan2019' as date) as Start_date,cast('08Sep2019' as date) as end_dt from dual union
select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('09Sep2019' as date) as Start_date,cast('20Jan2020' as date) as end_dt from dual union
select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('21Jan2020' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual
)
select x.Person_Id,
COALESCE(x.lag_start,x.min_date) as Prev_start_dt,
x.min_date as Current_Start_Dt,
COALESCE(x.lag_pos,x.position_id) as Pos_old
FROM
(select person_id,
position_id,
min(start_date) as min_date,
max(start_date) as max_date,
lag(max(start_date)) Over(Partition by Person_Id Order by max(start_date)) as lag_start,
lag(position_id) Over(Partition by Person_Id Order by min(start_date)) as lag_pos
from cte
group by person_id, position_id) x
inner join
(select person_id,
count(distinct position_id) as cnt
from cte
group by person_id) y
ON x.person_id=y.person_id
Where x.Position_id<>x.lag_pos or y.cnt=1
The idea is to group the information at a person and position level and then use the lag function to determine if there is a change. Cnt=1 filter is applied to get the cases where there is no position change. Hope this helps.

Fetch next record within a table

I have the following table
EMP_ID ,DATETIME_OF_MOVEMENT,CITY ,RANK
2258325 ,1/18/2020 5:37 ,London ,1
2258325 ,1/19/2020 11:01 ,Manchester ,2
2258325 ,1/20/2020 15:06 ,London ,3
2656700 ,1/20/2020 23:59 ,London ,1
2656700 ,1/21/2020 6:48 ,Manchester ,2
2656700 ,1/21/2020 6:48 ,Liverpool ,3
2656700 ,1/26/2020 10:47 ,London ,4
6631583 ,1/18/2020 18:00 ,London ,1
6631583 ,1/19/2020 14:25 ,Manchester ,2
6631583 ,1/20/2020 8:53 ,Liverpool ,3
6631583 ,1/20/2020 14:48 ,Manchester ,4
6631583 ,1/21/2020 11:34 ,London ,5
I want a query to get the employee who were in london and come back to london.
the firt location should be london second is the first location after london and third location should be london
I used the following query but it miss some employees
select emp_id , date_of_movement as first_movement , city as first_city ,lead
(DATETIME_OF_MOVEMENT, 1) over ( partition by emp_id order by DATETIME_OF_MOVEMENT) as second_movement ,
lead (city , 1) over ( partition by emp_id order by DATETIME_OF_MOVEMENT) as second_city ,
lead (DATETIME_OF_MOVEMENT, 2) over ( partition by emp_id order by DATETIME_OF_MOVEMENT) as third_movement ,
lead (city , 1) over ( partition by emp_id order by DATETIME_OF_MOVEMENT) as third_city ,
from table
result of the code
CUSTOMER_ID,first_movement ,first_city,second_movment ,second_movement,third_movment ,third_city
2258325 ,1/18/2020 5:37 ,London ,1/19/2020 11:01,Manchester ,1/20/2020 15:06,London
2656700 ,1/20/2020 23:59,London ,1/21/2020 6:48 ,Manchester ,1/21/2020 6:48 ,Liverpool
6631583 ,1/18/2020 18:00,London ,1/19/2020 14:25,Manchester ,1/20/2020 8:53 ,Liverpool
This code catch the employee it their track of movement ( ex. emp_id : 2258325 )
1 - London
2 - any other city
3 - London
It will not works fine If the movement of the employee like the following
1 - london
2 - any other city
3 - any other city
4 - London
i want the result to be like
CUSTOMER_ID,first_movement ,first_city,second_movement,second_city,third_movement ,third_city
2258325 ,1/18/2020 5:37 ,London ,1/19/2020 11:01,Manchester ,1/20/2020 15:06,London
2656700 ,1/20/2020 23:59,London ,1/21/2020 6:48 ,Manchester ,1/26/2020 10:47,London
6631583 ,1/18/2020 18:00,London ,1/19/2020 14:25,Manchester ,1/21/2020 11:34,London
Any suggestion please?
WITH YOUR_TABLE (EMP_ID,
DATETIME_OF_MOVEMENT,
CITY,
RANK_)
AS (SELECT 2258325,
'1/18/2020 5:37',
'London',
1
FROM DUAL
UNION ALL
SELECT 2258325,
'1/19/2020 11:01',
'Manchester',
2
FROM DUAL
UNION ALL
SELECT 2258325,
'1/20/2020 15:06',
'London',
3
FROM DUAL
UNION ALL
SELECT 2656700,
'1/20/2020 23:59',
'London',
1
FROM DUAL
UNION ALL
SELECT 2656700,
'1/21/2020 6:48',
'Manchester',
2
FROM DUAL
UNION ALL
SELECT 2656700,
'1/21/2020 6:48',
'Liverpool',
3
FROM DUAL
UNION ALL
SELECT 2656700,
'1/26/2020 10:47',
'London',
4
FROM DUAL
UNION ALL
SELECT 6631583,
'1/18/2020 18:00',
'London',
1
FROM DUAL
UNION ALL
SELECT 6631583,
'1/19/2020 14:25',
'Manchester',
2
FROM DUAL
UNION ALL
SELECT 6631583,
'1/20/2020 8:53',
'Liverpool',
3
FROM DUAL
UNION ALL
SELECT 6631583,
'1/20/2020 14:48',
'Manchester',
4
FROM DUAL
UNION ALL
SELECT 6631583,
'1/21/2020 11:34',
'London',
5
FROM DUAL
UNION ALL
SELECT 6631583,
'1/22/2020 14:48',
'Manchester',
6
FROM DUAL
UNION ALL
SELECT 6631583,
'1/24/2020 11:34',
'London',
7
FROM DUAL) -- YOUR QUERY STARTS FROM HERE SELECT EMP_ID,
MAX (CASE WHEN MINRN = RANK_ THEN DATETIME_OF_MOVEMENT END)
AS first_movement,
MAX (CASE WHEN MINRN = RANK_ THEN CITY END) AS first_CITY,
MAX (CASE WHEN MINRN + 1 = RANK_ THEN DATETIME_OF_MOVEMENT END)
AS SECOND_movement,
MAX (CASE WHEN MINRN + 1 = RANK_ THEN CITY END) AS SECOND_CITY,
MAX (CASE WHEN MAXRN = RANK_ THEN DATETIME_OF_MOVEMENT END)
AS THIRD_movement,
MAX (CASE WHEN MAXRN = RANK_ THEN CITY END) AS THIRD_CITY
FROM (SELECT T.*,
MAX (CASE WHEN CITY = 'London' THEN RANK_ END)
OVER (PARTITION BY EMP_ID)
AS MAXRN,
MIN (CASE WHEN CITY = 'London' THEN RANK_ END)
OVER (PARTITION BY EMP_ID)
AS MINRN
FROM YOUR_TABLE T) WHERE MAXRN - MINRN > 1 GROUP BY EMP_ID;
check this it is not works #Tejash
result should be like this:
SELECT emp_id,
Lead (datetime_of_movement, 0)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement ASC) AS first_movement,
Lead (city, 0)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement ASC) AS first_city,
Lead (datetime_of_movement, 1)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement ASC) AS second_movement,
Lead (city, 1)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement ASC) AS second_city,
Lead (datetime_of_movement, 0)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement DESC) AS third_movement,
Lead (city, 0)
OVER (
partition BY emp_id
ORDER BY datetime_of_movement DESC) AS third_city,
FROM table
WHERE frist_city = "London" AND third_city = "London"
I couldn't test this SQL but maybe helpful. please let me know if it works for you.
I think you need a record starting from London then next record and the last London record. You can use the combination of the conditional aggregate and analytical function as following:
SQL> WITH YOUR_TABLE (
2 EMP_ID,
3 DATETIME_OF_MOVEMENT,
4 CITY,
5 RANK
6 ) AS
7 (
8 SELECT 2258325 ,'1/18/2020 5:37' ,'London' ,1 FROM DUAL UNION ALL
9 SELECT 2258325 ,'1/19/2020 11:01' ,'Manchester' ,2 FROM DUAL UNION ALL
10 SELECT 2258325 ,'1/20/2020 15:06' ,'London' ,3 FROM DUAL UNION ALL
11 SELECT 2656700 ,'1/20/2020 23:59' ,'London' ,1 FROM DUAL UNION ALL
12 SELECT 2656700 ,'1/21/2020 6:48' ,'Manchester' ,2 FROM DUAL UNION ALL
13 SELECT 2656700 ,'1/21/2020 6:48' ,'Liverpool' ,3 FROM DUAL UNION ALL
14 SELECT 2656700 ,'1/26/2020 10:47' ,'London' ,4 FROM DUAL UNION ALL
15 SELECT 6631583 ,'1/18/2020 18:00' ,'London' ,1 FROM DUAL UNION ALL
16 SELECT 6631583 ,'1/19/2020 14:25' ,'Manchester' ,2 FROM DUAL UNION ALL
17 SELECT 6631583 ,'1/20/2020 8:53' ,'Liverpool' ,3 FROM DUAL UNION ALL
18 SELECT 6631583 ,'1/20/2020 14:48' ,'Manchester' ,4 FROM DUAL UNION ALL
19 SELECT 6631583 ,'1/21/2020 11:34' ,'London' ,5 FROM DUAL
20 )
21 -- YOUR QUERY STARTS FROM HERE
22 SELECT
23 EMP_ID,
24 MAX(CASE WHEN MINRN = RANK THEN DATETIME_OF_MOVEMENT END) AS first_movement,
25 MAX(CASE WHEN MINRN = RANK THEN CITY END) AS first_CITY,
26 MAX(CASE WHEN MINRN + 1 = RANK THEN DATETIME_OF_MOVEMENT END) AS SECOND_movement,
27 MAX(CASE WHEN MINRN + 1 = RANK THEN CITY END) AS SECOND_CITY,
28 MAX(CASE WHEN MAXRN = RANK THEN DATETIME_OF_MOVEMENT END) AS THIRD_movement,
29 MAX(CASE WHEN MAXRN = RANK THEN CITY END) AS THIRD_CITY
30 FROM
31 (
32 SELECT T.*,
33 MAX(CASE WHEN CITY = 'London' THEN RANK END) OVER(PARTITION BY EMP_ID) AS MAXRN,
34 MIN(CASE WHEN CITY = 'London' THEN RANK END) OVER(PARTITION BY EMP_ID) AS MINRN
35 FROM YOUR_TABLE T
36 )
37 WHERE MAXRN - MINRN > 1
38 GROUP BY EMP_ID;
EMP_ID FIRST_MOVEMENT FIRST_CITY SECOND_MOVEMENT SECOND_CIT THIRD_MOVEMENT THIRD_CITY
---------- --------------- ---------- --------------- ---------- --------------- ----------
2258325 1/18/2020 5:37 London 1/19/2020 11:01 Manchester 1/20/2020 15:06 London
2656700 1/20/2020 23:59 London 1/21/2020 6:48 Manchester 1/26/2020 10:47 London
6631583 1/18/2020 18:00 London 1/19/2020 14:25 Manchester 1/21/2020 11:34 London
SQL>
Cheers!!
You can try this below script. But this will return only onle row as only one EMP has city London where Rank = 3 ( and as per explanation your concern is location 3 as well)
DEMO HERE
SELECT
DISTINCT A.EMP_ID CUSTOMER_ID,
A.DATETIME_OF_MOVEMENT first_movement ,A.city first_city,
B.DATETIME_OF_MOVEMENT secondt_movement,B.city second_city,
C.DATETIME_OF_MOVEMENT third_movement ,C.city third_city
FROM your_table A
INNER JOIN your_table B ON A.Rank = B.Rank - 1 AND A.EMP_ID = B.EMP_ID
INNER JOIN your_table C ON A.Rank = C.Rank - 2 AND A.EMP_ID = C.EMP_ID
WHERE A.RANK = 1
AND C.City = 'London'
New logic if the last city is not the third city-
DEMO HERE
WITH CTE AS
(
SELECT A.EMP_ID,A.DATETIME_OF_MOVEMENT,A.CITY,A.RANK,
CASE WHEN A.RANK > 2 THEN 3 ELSE A.Rank END NEW_RANK
FROM your_table A
WHERE A.RANK IN (1,2)
OR A.RANK = (SELECT MAX(Rank) FROM your_table B WHERE B.EMP_ID = A.EMP_ID)
)
SELECT
A.EMP_ID CUSTOMER_ID,
A.DATETIME_OF_MOVEMENT first_movement ,A.city first_city,
B.DATETIME_OF_MOVEMENT secondt_movement,B.city second_city,
C.DATETIME_OF_MOVEMENT third_movement ,C.city third_city
FROM CTE A
INNER JOIN CTE B ON A.NEW_RANK = B.NEW_RANK - 1 AND A.EMP_ID = B.EMP_ID
INNER JOIN CTE C ON A.NEW_RANK = C.NEW_RANK - 2 AND A.EMP_ID = C.EMP_ID
WHERE A.NEW_RANK = 1
AND C.City = 'London'

Oracle SQL: Find the date 7 days ahead of a specified date excluding Sundays and other specific dates

I need to find what the date is 7 days ahead of any given date. The start date can be any date, however, the end date should not be a Sunday or a day marked as a holiday. There can only ever be 2 consecutive holiday days.
I have code that works, however, it's very long-winded. Is there potentially a simpler solution?
Also, if the required date range changed at some point in the future or the possible number of consecutive holidays changed, the script would need to be updated in multiple places, if this could be reduced then that would be great.
I already have a table (CALENDAR) containing a substantial range of dates, their day of the week and whether the date is considered a holiday. Something like this:
START_DATE, DAY_OF_WEEK, HOLIDAY
10-DEC-17 , Sun , 0
11-DEC-17 , Mon , 0
12-DEC-17 , Tue , 0
13-DEC-17 , Wed , 0
14-DEC-17 , Thu , 0
15-DEC-17 , Fri , 0
16-DEC-17 , Sat , 0
17-DEC-17 , Sun , 0
18-DEC-17 , Mon , 0
19-DEC-17 , Tue , 0
20-DEC-17 , Wed , 0
21-DEC-17 , Thu , 0
22-DEC-17 , Fri , 0
23-DEC-17 , Sat , 0
24-DEC-17 , Sun , 0
25-DEC-17 , Mon , 1
26-DEC-17 , Tue , 1
27-DEC-17 , Wed , 0
28-DEC-17 , Thu , 0
29-DEC-17 , Fri , 0
30-DEC-17 , Sat , 0
31-DEC-17 , Sun , 0
01-JAN-18 , Mon , 1
etc...
The expected OUTPUT would be something like:
START_DATE, END_DATE
10-DEC-17, 18-DEC-17
11-DEC-17, 18-DEC-17
12-DEC-17, 19-DEC-17
13-DEC-17, 20-DEC-17
14-DEC-17, 21-DEC-17
15-DEC-17, 22-DEC-17
16-DEC-17, 23-DEC-17
17-DEC-17, 27-DEC-17
18-DEC-17, 27-DEC-17
19-DEC-17, 27-DEC-17
20-DEC-17, 27-DEC-17
21-DEC-17, 28-DEC-17
22-DEC-17, 29-DEC-17
23-DEC-17, 30-DEC-17
24-DEC-17, 02-JAN-18
25-DEC-17, 02-JAN-18
26-DEC-17, 02-JAN-18
27-DEC-17, 03-JAN-18
28-DEC-17, 04-JAN-18
etc...
Below is my existing code. My approach is that as there can only ever be 3 consecutive excluded days (a Sunday followed by 2 holiday days), then I check 4 days ahead for each date and then take the first one which is not an excluded date. One of the 4 should always be a valid end date.
with temp as
(
select
start_date,
case
when lead(day_of_week, 7) over(order by start_date) = 'Sun'
or lead(holiday, 7) over(order by start_date) = 1
then null
else
lead(start_date, 7) over(order by start_date)
end as days_7,
case
when lead(day_of_week, 8) over(order by start_date) = 'Sun'
or lead(holiday, 8) over(order by start_date) = 1
then null
else
lead(start_date, 8) over(order by start_date)
end as days_8,
case
when lead(day_of_week, 9) over(order by start_date) = 'Sun'
or lead(holiday, 9) over(order by start_date) = 1
then null
else
lead(start_date, 9) over(order by start_date)
end as days_9,
case
when lead(day_of_week, 10) over(order by start_date) = 'Sun'
or lead(holiday, 10) over(order by start_date) = 1
then null
else
lead(start_date, 10) over(order by start_date)
end as days_10
from
calendar
)
select
start_date,
COALESCE(days_7, days_8, days_9, days_10) as end_date
from
temp
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Calendar( START_DATE, HOLIDAY ) AS
SELECT TO_DATE( '10-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '11-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '12-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '13-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '14-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '15-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '16-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '17-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '18-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '19-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '20-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '21-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '22-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '23-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '24-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '25-DEC-17', 'DD-MON-YY' ), 1 FROM DUAL UNION ALL
SELECT TO_DATE( '26-DEC-17', 'DD-MON-YY' ), 1 FROM DUAL UNION ALL
SELECT TO_DATE( '27-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '28-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '29-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '30-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '31-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '01-JAN-18', 'DD-MON-YY' ), 1 FROM DUAL;
Query 1:
SELECT start_date,
LEAD( end_date, 7 ) OVER ( ORDER BY start_date ) AS end_date
FROM (
SELECT start_date,
LAST_VALUE(
CASE
WHEN Holiday = 0
AND start_date - TRUNC( start_date, 'IW' ) < 6
THEN start_date
END
) IGNORE NULLS OVER ( ORDER BY start_date DESC ) AS End_date
FROM Calendar
)
Results:
| START_DATE | END_DATE |
|----------------------|----------------------|
| 2017-12-10T00:00:00Z | 2017-12-18T00:00:00Z |
| 2017-12-11T00:00:00Z | 2017-12-18T00:00:00Z |
| 2017-12-12T00:00:00Z | 2017-12-19T00:00:00Z |
| 2017-12-13T00:00:00Z | 2017-12-20T00:00:00Z |
| 2017-12-14T00:00:00Z | 2017-12-21T00:00:00Z |
| 2017-12-15T00:00:00Z | 2017-12-22T00:00:00Z |
| 2017-12-16T00:00:00Z | 2017-12-23T00:00:00Z |
| 2017-12-17T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-18T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-19T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-20T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-21T00:00:00Z | 2017-12-28T00:00:00Z |
| 2017-12-22T00:00:00Z | 2017-12-29T00:00:00Z |
| 2017-12-23T00:00:00Z | 2017-12-30T00:00:00Z |
| 2017-12-24T00:00:00Z | (null) |
| 2017-12-25T00:00:00Z | (null) |
| 2017-12-26T00:00:00Z | (null) |
| 2017-12-27T00:00:00Z | (null) |
| 2017-12-28T00:00:00Z | (null) |
| 2017-12-29T00:00:00Z | (null) |
| 2017-12-30T00:00:00Z | (null) |
| 2017-12-31T00:00:00Z | (null) |
| 2018-01-01T00:00:00Z | (null) |
given holidays table:
with holidays as (
select to_date('10-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('11-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 0 holiday from dual
union all
select to_date('12-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 0 holiday from dual
union all
select to_date('13-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('14-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('15-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('16-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('17-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('18-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 0 holiday from dual
union all
select to_date('19-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 0 holiday from dual
union all
select to_date('20-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('21-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('22-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('23-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('24-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('25-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 1 holiday from dual
union all
select to_date('26-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 1 holiday from dual
union all
select to_date('27-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('28-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('29-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('30-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('31-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('01-JAN-18','dd-MON-YY') as mydate , 'Mon' as myday, 1 holiday from dual),
Here I find working days and then use first row to get the desired date
working as (
select holidays.*, case when myday='Sun' or holiday=1
then 0 else 1 end as working_day from holidays
)
select mydate from (
select mydate from working where
mydate>=to_date('21/12/2017','dd/mm/rrrr')+7
order by (case when working_day=0 then null else mydate end) asc nulls last
) where rownum=1

Calculating a summary of previously calculated data

Quick question about summary data:
I have the below code which will pull sales information and put it into a month/year grid, which is terrific (http://sqlfiddle.com/#!3/9d79e/1):
WITH
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12),
years AS (SELECT 2011 AS yr UNION ALL SELECT yr + 1 FROM years WHERE yr < 2015),
invoices AS (
SELECT CAST('2013-06-27' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-07-29' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-10-30' AS date) AS InvoiceDate, 40 AS MarginAmount
)
-- End data setup, real work begins here
SELECT * FROM
(
SELECT
months.mon, years.yr, COALESCE(SUM(inv.MarginAmount), 0) AS MarginAmount
FROM
months
CROSS JOIN years
LEFT OUTER JOIN invoices inv ON ( (YEAR(inv.InvoiceDate) = years.yr) AND (MONTH(inv.InvoiceDate) = months.mon) )
GROUP BY
months.mon, years.yr
) AS source
PIVOT
(
MAX(MarginAmount)
FOR yr in ([2011], [2012], [2013], [2014], [2015])
)
AS pvt
ORDER BY mon
I was wondering how I could change two things:
Replace the numbers 1 - 11 with the names of the months of the year and
Create a line at the bottom of the table summarizing the information above it, where the mon column would have the word 'Total'
Any help would be greatly appreciated
e.g The sum of all sales in 2012 would be displayed at the bottom of the 2012 column
Question 1. Replace numbers
To replace the numbers, you can for instance change this:
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12)
to
months AS (SELECT 1 AS mon, 'Jan' name UNION ALL SELECT mon + 1, months.name FROM months WHERE mon < 12)
Question 2. Grand totals
To create a bottom line with totals you can either use grouping sets (your query seems to be SQL Server, don't know whether SQL Server supports that, please specify):
group
by grouping sets
( ()
, (full list)
)
or add a union to the query:
with myresults as (the whole thing)
select 1 ordering
, myresults.columns-minus-total
, myresults.something subtotal
from myresults
union all
select 2 ordering
, myresults.columns-minus-total
, sum(something) grandtotal
from myresults
order
by 1
, ...other...
Complete example using Microsoft SQL Server 2008 R2
Original code was prettified and without dependencies on tables:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select *
from ( select months.mon
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by months.mon
, years.yr
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by mon
Adding the text and grand totals leads to:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select case
when mon is null
then 'Total'
else cast(mon as varchar)
end
, monname
, [2011]
, [2012]
, [2013]
, [2014]
, [2015]
from ( select months.mon
, months.monname
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by grouping sets
( (months.mon, months.monname, years.yr)
, (years.yr)
)
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by coalesce(mon, 100)

(Not) complicated sql query !

LookupTable:
userid, mobileid, startedate, enddate , owner
1 , 1 , 12-12-2000, 01-01-2001, asd
2 , 2 , 12-12-2000, 01-01-2001, dgs
3 , 3 , 02-01-2001, 01-01-2002, sdg
4 , 4 , 12-12-2000, 01-01-2001, sdg
UserInfoTable:
userid, firstname, lastname, address
1 , tom , do , test
2 , sam , smith , asds
3 , john , saw , asdasda
4 , peter , winston , near by
Mobile:
Mobileid, Name , number, imeinumber
1 , apple , 123 , 1111111
2 , nokia , 456 , 2222222
3 , vodafone , 789 , 3333333
CallLogs:
id , Mobileid, callednumbers (string), date , totalduration
1 , 1 , 123,123,321 , 13-12-2000 , 30
2 , 1 , 123,123,321 , 14-12-2000 , 30
3 , 2 , 123,123,321 , 13-12-2000 , 30
4 , 2 , 123,123,321 , 14-12-2000 , 30
5 , 3 , 123,123,321 , 13-12-2000 , 30
6 , 3 , 123,123,321 , 14-12-2000 , 30
7 , 1 , 123,123,321 , 13-01-2002 , 30
8 , 1 , 123,123,321 , 14-01-2002 , 30
I want a query which will return me the following:
firstname, lastname, mobile.name as mobilename, callednumbers (as concatinated strings from different rows in CallLogs table) and need it for year 2000
example:
firstname, lastname, mobilename, callednumbers
tom , do , apple , 123,123,321, 123,123,321
sam , smith , nokia , 123,123,321, 123,123,321
peter , winston , apple , 123,123,321, 123,123,321
any help will be highly appreciated...
I have tried this but no sucess.. tom is getting sams calls and vice versa. I am using sql server.
SELECT DISTINCT firstname,
lastname,
mobilename,
callednumbers
FROM ([testdatabase].[dbo].[LookupTable] lt
INNER JOIN [testdatabase].[dbo].[UserInfoTable] user1
ON lt.userid = user1.id)
INNER JOIN [testdatabase].[dbo].[Mobile] device1
ON lt.mobileid = device1.id
INNER JOIN [testdatabase].[dbo].[CallLogs] log1
ON lt.mobileid = log1.deviceid
WHERE lt.starttime LIKE '%2000%'
ORDER BY firstname
DECLARE #LookupTable TABLE (
userid INT,
mobileid INT,
startedate DATETIME,
enddate DATETIME,
owner CHAR(3))
INSERT INTO #LookupTable
SELECT 1, 1, '20001212 00:00:00.000', '20010101 00:00:00.000', N'asd' UNION ALL
SELECT 2, 2, '20001212 00:00:00.000', '20010101 00:00:00.000', N'dgs' UNION ALL
SELECT 3, 3, '20010102 00:00:00.000', '20020101 00:00:00.000', N'sdg' UNION ALL
SELECT 4, 4, '20001212 00:00:00.000', '20010101 00:00:00.000', N'sdg'
DECLARE #UserInfoTable TABLE (
userid INT,
firstname VARCHAR(10),
lastname VARCHAR(10),
address VARCHAR(10))
INSERT INTO #UserInfoTable
SELECT 1, N'tom', N'do', N'test' UNION ALL
SELECT 2, N'sam', N'smith', N'asds' UNION ALL
SELECT 3, N'john', N'saw', N'asdasda' UNION ALL
SELECT 4, N'peter', N'winston', N'near by'
DECLARE #Mobile TABLE (
mobileid INT,
name VARCHAR(10),
number INT,
imeinumber INT )
INSERT INTO #Mobile
SELECT 1, N'apple', 123, 1111111 UNION ALL
SELECT 2, N'nokia', 456, 2222222 UNION ALL
SELECT 3, N'vodafone', 789, 3333333
DECLARE #CallLogs TABLE (
id INT,
mobileid INT,
callednumbers VARCHAR(50),
[date] DATETIME,
totalduration INT )
INSERT INTO #CallLogs
SELECT 1, 1, N'123,123,321', '20001213 00:00:00.000', 30 UNION ALL
SELECT 2, 1, N'123,123,321', '20001214 00:00:00.000', 30 UNION ALL
SELECT 3, 2, N'123,123,321', '20001213 00:00:00.000', 30 UNION ALL
SELECT 4, 2, N'123,123,321', '20001214 00:00:00.000', 30 UNION ALL
SELECT 5, 3, N'123,123,321', '20001213 00:00:00.000', 30 UNION ALL
SELECT 6, 3, N'123,123,321', '20001214 00:00:00.000', 30 UNION ALL
SELECT 7, 1, N'123,123,321', '20020113 00:00:00.000', 30 UNION ALL
SELECT 8, 1, N'123,123,321', '20020114 00:00:00.000', 30
SELECT DISTINCT firstname,
lastname,
device1.name AS mobilename,
stuff((select ',' + callednumbers
from #CallLogs log1
where lt.mobileid = log1.mobileid
for xml path('')), 1, 1, '') AS callednumbers
FROM (#LookupTable lt
INNER JOIN #UserInfoTable user1
ON lt.userid = user1.userid)
INNER JOIN #Mobile device1
ON lt.mobileid = device1.mobileid
WHERE lt.startedate > '20000101' AND startedate < '20010101'
ORDER BY firstname