Add business days to another table using a date table in SQL - sql

I have these 2 tables with values:
create table FieldTable (
FieldId int,
FieldName varchar(256),
FieldValue sql_variant);
go
insert into FieldTable values (1, 'ABC', '04/17/2020');
go
create table DatbeTable (
Dt date,
DayType char);
go
insert into DatbeTable values ('2020-04-01','B');
insert into DatbeTable values ('2020-04-02','B');
insert into DatbeTable values ('2020-04-03','B');
insert into DatbeTable values ('2020-04-04','W');
insert into DatbeTable values ('2020-04-05','W');
insert into DatbeTable values ('2020-04-06','B');
insert into DatbeTable values ('2020-04-07','B');
insert into DatbeTable values ('2020-04-08','B');
insert into DatbeTable values ('2020-04-09','B');
insert into DatbeTable values ('2020-04-10','B');
insert into DatbeTable values ('2020-04-11','W');
insert into DatbeTable values ('2020-04-12','W');
insert into DatbeTable values ('2020-04-13','B');
insert into DatbeTable values ('2020-04-14','B');
insert into DatbeTable values ('2020-04-15','B');
insert into DatbeTable values ('2020-04-16','B');
insert into DatbeTable values ('2020-04-17','B');
insert into DatbeTable values ('2020-04-18','W');
insert into DatbeTable values ('2020-04-19','W');
insert into DatbeTable values ('2020-04-20','B');
insert into DatbeTable values ('2020-04-21','B');
insert into DatbeTable values ('2020-04-22','B');
insert into DatbeTable values ('2020-04-23','B');
insert into DatbeTable values ('2020-04-24','B');
insert into DatbeTable values ('2020-04-25','W');
insert into DatbeTable values ('2020-04-26','W');
insert into DatbeTable values ('2020-04-27','B');
insert into DatbeTable values ('2020-04-28','B');
insert into DatbeTable values ('2020-04-29','B');
insert into DatbeTable values ('2020-04-30','B');
go
I want to add 3 business days from the FieldValue date to the new column: NewFieldValue for that row.
select
FieldId,
FieldName,
FieldValue--,
--NewFieldValue
into #temp
from FieldTable ft
join DatbeTable d
on format(try_convert(date, ft.FieldValue), 'd', 'en-us') = format(try_convert(date, d.Dt), 'd', 'en-us');
go
I can't really figure out how to use the 2 tables to get this below result:
FieldId FieldName FieldValue NewFieldValue
------- --------- ---------- -------------
1 ABC 04/17/2020 04/22/2020

You can use row_number() to find out the nth business day from your base date
select
FieldId,
FieldName,
FieldValue,
d.Dt as NewFieldValue
from FieldTable ft
cross apply
(
select x.Dt, day_no = row_number() over (ORDER BY x.Dt)
from DatbeTable x
where x.Dt > try_convert(date, ft.FieldValue)
and x.DayType = 'B' -- business day only
) d
where d.day_no = 3 -- add 3 business days
Note : Don't convert the date to string for comparison.
PS : you should explain what is B and W. Thought it is pretty obvious that it is Business and Weekend but nevertheless, it is clearer if explain the related columns in your table.

Related

How to calculate the average value of following n rows based on another column - SQL (Oracle)

I am trying to calculate average monthly value of premiums for each POLICY_ID in monthly basis as shown below. When a customer updates his/her yearly payment frequency to a value different than 12, I need to manually calculate the average monthly value for the PREMIUM. How can I achieve the values shown in MONTHLY _PREMIUM_DESIRED?
Thanks in advance.
Note: Oracle version 12c
What I've tried:
SELECT
T.*,
SUM(PREMIUM) OVER(PARTITION BY T.POLICY_ID ORDER BY T.POLICY_ID, T.PAYMENT_DATE ROWS BETWEEN CURRENT ROW AND 12/T.YEARLY_PAYMENT_FREQ-1 FOLLOWING ) / (12/T.YEARLY_PAYMENT_FREQ) MONTLY_PREMIUM_CALCULATED
FROM MYTABLE T
;
Code for data:
DROP TABLE MYTABLE;
CREATE TABLE MYTABLE (POLICY_ID NUMBER(11), PAYMENT_DATE DATE, PREMIUM NUMBER(5), YEARLY_PAYMENT_FREQ NUMBER(2),MONTHLY_PREMIUM_DESIRED NUMBER(5));
INSERT INTO MYTABLE VALUES (1, DATE '2014-10-01',120,12,120);
INSERT INTO MYTABLE VALUES (1, DATE '2014-11-01',360,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2014-12-01',0,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-01-01',0,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-02-01',360,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-03-01',0,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-04-01',0,4,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-05-01',720,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-06-01',0,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-07-01',0,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-08-01',0,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-09-01',0,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-10-01',0,2,120);
INSERT INTO MYTABLE VALUES (1, DATE '2015-11-01',120,12,120);
INSERT INTO MYTABLE VALUES (2, DATE '2015-01-01',60,3,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-02-01',0,3,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-03-01',0,3,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-04-01',0,3,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-05-01',180,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-06-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-07-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-08-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-09-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-10-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-11-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2015-12-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-01-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-02-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-03-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-04-01',0,1,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-05-01',15,12,15);
INSERT INTO MYTABLE VALUES (2, DATE '2016-06-01',15,12,15);
SELECT * FROM MYTABLE;
EDIT:
Regardless from payment frequency PREMIUM amount can also be changed by customer. Below, for the POLICY_ID = 1, I have added new records starting from "2015/11/01" to demonstrate this situation. In this case, average monthly premium increased from 120 to 240.
Also removed the screenshot to make the question more readable.
DROP TABLE MYTABLE2;
CREATE TABLE MYTABLE2 (POLICY_ID NUMBER(11), PAYMENT_DATE DATE, PREMIUM NUMBER(5), YEARLY_PAYMENT_FREQ NUMBER(2),MONTHLY_PREMIUM_DESIRED NUMBER(5));
INSERT INTO MYTABLE2 VALUES (1, DATE '2014-10-01',120,12,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2014-11-01',360,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2014-12-01',0,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-01-01',0,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-02-01',360,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-03-01',0,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-04-01',0,4,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-05-01',720,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-06-01',0,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-07-01',0,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-08-01',0,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-09-01',0,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-10-01',0,2,120);
INSERT INTO MYTABLE2 VALUES (1, DATE '2015-11-01',240,12,240);
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-12-01',240,12,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-01-01',960,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-02-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-03-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-04-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-05-01',960,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-06-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-07-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (1, DATE '2016-08-01',0,4,240); --newly added records
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-01-01',60,3,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-02-01',0,3,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-03-01',0,3,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-04-01',0,3,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-05-01',180,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-06-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-07-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-08-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-09-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-10-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-11-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2015-12-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-01-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-02-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-03-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-04-01',0,1,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-05-01',15,12,15);
INSERT INTO MYTABLE2 VALUES (2, DATE '2016-06-01',15,12,15);
SELECT * FROM MYTABLE2;
I think the calculation is:
select t.*,
premium / (12 / yearly_payment_freq)) as monthly_premium_calculated
from mytable t;
EDIT:
I see, you also need this spread over the intermediate months. So you can assign the groups by counting the number of non-zero payments. Then:
select t.*,
( max(premium) over (partition by policy_id, grp) /
(12 / yearly_payment_freq)
) as monthly_premium_calculated
from (select t.*,
sum(case when premium > 0 then 1 else 0 end) over (partition by policy_id order by payment_date) as grp
from mytable t
) t;
Here is a db<>fiddle (it uses Postgres because that is easier to set up than Oracle).

SQL Finding multiple combinations in 2 tables (with all records)

I have two tables, one with some user configurations (#USERCONFIG) and the other (#COMBINATIONS), multiples combinations of configurations I need to find in the first table.
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU CHAR(10))
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10))
INSERT INTO #COMBINATIONS VALUES (1, 'ABC300')
INSERT INTO #COMBINATIONS VALUES (1, 'ABC400')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC100')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC500')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC200')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC300')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC400')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC600')
With this example data, I want the resultset to look like this:
'SMITHJ', '2'
'SMITHA', '1'
'SMITHC', '2'
Where it will return all users that have a match of configurations from the combinations table.
Any help would be appreciated.
The following will list users and the complete combinations they have. If it helps, you can think of it as the recipe-ingredient and user-ingredient textbook problem:
SELECT alluser.USERID, index_menu.INDEX1
FROM (SELECT DISTINCT USERID FROM #USERCONFIG) AS alluser
CROSS JOIN #COMBINATIONS AS index_menu
LEFT JOIN #USERCONFIG AS user_menu ON alluser.USERID = user_menu.USERID AND index_menu.MENU = user_menu.MENU
GROUP BY alluser.USERID, index_menu.INDEX1
HAVING COUNT(index_menu.MENU) = COUNT(user_menu.MENU)
This snippet will get that result:
IF OBJECT_ID('tempdb..#COMBINATIONS') IS NOT NULL DROP TABLE #COMBINATIONS;
IF OBJECT_ID('tempdb..#USERCONFIG') IS NOT NULL DROP TABLE #USERCONFIG;
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU VARCHAR(10));
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10));
INSERT INTO #COMBINATIONS (INDEX1, MENU) VALUES
(1, 'ABC301'),
(1, 'ABC401'),
(2, 'ABC102'),
(2, 'ABC502'),
(2, 'ABC602');
INSERT INTO #USERCONFIG (USERID, MENU) VALUES
('SMITHJ', 'ABC102'),
('SMITHJ', 'ABC502'),
('SMITHJ', 'ABC602'),
('SMITHC', 'ABC102'),
('SMITHC', 'ABC502'),
('SMITHA', 'ABC102'),
('SMITHA', 'ABC200'),
('SMITHA', 'ABC301'),
('SMITHA', 'ABC401'),
('SMITHA', 'ABC602');
SELECT USERID, INDEX1
FROM
(
SELECT uconf.USERID, comb.INDEX1,
COUNT(*) AS Total,
DENSE_RANK() OVER (PARTITION BY uconf.USERID ORDER BY COUNT(*) DESC, comb.INDEX1 ASC) AS Rnk
FROM #USERCONFIG uconf
INNER JOIN #COMBINATIONS comb
ON comb.MENU = uconf.MENU
GROUP BY uconf.USERID, INDEX1
) q
WHERE Rnk = 1
ORDER BY Total DESC, USERID;
Returns:
USERID INDEX1
SMITHJ 2
SMITHA 1
SMITHC 2

SQL Server: Find the group of records existing in another group of records

I'm new to SQL Server and I searched for a solution to find, if a group is included in another group.
The query result should be grp_id 2 because 'A'+'B' is included in grp 3 and 5.
The result should be the grp_id of the the groups, that are included in other groups. With this result i´ll make an update of another table, joined with the grp_id.
The result should be:
+----+
| id |
+----+
| 2 |
+----+
I stuck in SQL because I do not find a solution to compare the groups. The idea was using bitwise comparison. But for that I had to add the value of each item in a field. I think there could be an easier way.
Thank you and best regards!
Eric
create table tmp_grpid (grp_id int);
create table tmp_grp (grp_id int, item_val nvarchar(10));
insert into tmp_grpid(grp_id) values (1);
insert into tmp_grpid(grp_id) values (2);
insert into tmp_grpid(grp_id) values (3);
insert into tmp_grpid(grp_id) values (4);
insert into tmp_grpid(grp_id) values (5);
--
insert into tmp_grp(grp_id, item_val) values (1, 'A');
insert into tmp_grp(grp_id, item_val) values (2, 'A');
insert into tmp_grp(grp_id, item_val) values (2, 'B');
insert into tmp_grp(grp_id, item_val) values (3, 'A');
insert into tmp_grp(grp_id, item_val) values (3, 'B');
insert into tmp_grp(grp_id, item_val) values (3, 'C');
insert into tmp_grp(grp_id, item_val) values (4, 'A');
insert into tmp_grp(grp_id, item_val) values (4, 'C');
insert into tmp_grp(grp_id, item_val) values (4, 'D');
insert into tmp_grp(grp_id, item_val) values (5, 'A');
insert into tmp_grp(grp_id, item_val) values (5, 'B');
insert into tmp_grp(grp_id, item_val) values (5, 'E');
Geez!
Technically speaking, group one is found in all other groups right? So, first a cross join to itself would be best with the condition that the values are the same AND that the groups are different, but before we do that we need to know how many items belong to each group so that's why we have the first select as a group that includes the count of elements per group, then join that with the cross join...Hope this helps.
select distinct dist_grpid
from
(select grp_id, count(*) cc from tmp_grp group by grp_id) g
inner join
(
select dist.grp_id dist_grpid, tmp_grp.grp_id, count(*) cc
from
tmp_grp dist
cross join tmp_grp
where
dist.item_val = tmp_grp.item_val and
dist.grp_id != tmp_grp.grp_id
group by
dist.grp_id,
tmp_grp.grp_id
) cj on g.grp_id = cj.dist_grpid and g.cc = cj.cc

access convert to sql

how can i convert this access statement to sql ?
DELETE [Find duplicates for tBDEDom].* FROM [Find duplicates for tBDEDom];
CREATE TABLE #tBDEDom( Id int, Name VARCHAR(10))
insert into #tBDEDom values(1, 'abc')
insert into #tBDEDom values(2, 'mpo')
insert into #tBDEDom values(3, 'atc')
insert into #tBDEDom values(4, 'xyz')
insert into #tBDEDom values(5, 'abc')
insert into #tBDEDom values(6, 'xyz')
insert into #tBDEDom values(7, 'abc')
SELECT * FROM #tBDEDom
;with cte
AS(
SELECT *, ROW_NUMBER()OVER(partition by Name order by Name) AS [rank] FROM #tBDEDom
)
DELETE FROM cte where [rank]>1
SELECT * FROM #tBDEDom
DROP TABLE #tBDEDom

Sql Server query with date filter

I have a table like this;
ID int,
OrderedDate DateTime
I want to select only records of followed month.
For example result set:
ID OrderedDate
110 January
110 February
200 January
200 February
How can I write this query?
I think you want list of months that ID has orders in but with the months sorted by the month number instead of the name?
create table test21210
(
id int,
OrderedDate datetime
)
go
insert test21210 (id, OrderedDate) values (110, '1/1/2010')
insert test21210 (id, OrderedDate) values (110, '1/5/2010')
insert test21210 (id, OrderedDate) values (110, '1/10/2010')
insert test21210 (id, OrderedDate) values (110, '2/2/2010')
insert test21210 (id, OrderedDate) values (110, '2/4/2010')
insert test21210 (id, OrderedDate) values (110, '2/6/2010')
insert test21210 (id, OrderedDate) values (200, '1/3/2010')
insert test21210 (id, OrderedDate) values (200, '1/5/2010')
insert test21210 (id, OrderedDate) values (200, '1/7/2010')
insert test21210 (id, OrderedDate) values (200, '1/9/2010')
insert test21210 (id, OrderedDate) values (200, '2/3/2010')
insert test21210 (id, OrderedDate) values (200, '2/5/2010')
insert test21210 (id, OrderedDate) values (200, '2/7/2010')
insert test21210 (id, OrderedDate) values (200, '2/9/2010')
go
with idmonth (id, MonthNumber) as
(
select id, MONTH(ordereddate) as 'MonthNumber'
from test21210
group by id, MONTH(ordereddate)
)
select id, DATENAME(MONTH, STR(MonthNumber)+'/1/2000')
from idmonth
order by id, MonthNumber
The question seems a bit unclear. But the example makes it look like you are wanting to sort by ID then by month name. If so, then I think this will do it. I don't have SQL Server to test it, so I'm sure it has syntax or other errors.
SELECT ID, DATENAME(month, OrderedDate) AS OrderedDate from table
ORDER BY 1, MONTH( OrderedDate )