Sql Server query with date filter - sql

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 )

Related

How to select distinct multi-column values in Oracle SQL?

I am trying to get distinct values with multi column select.
Sample table:
CREATE TABLE DUP_VALUES (ID NUMBER, NAME VARCHAR2(64));
INSERT INTO DUP_VALUES values (1, 'TEST1');
INSERT INTO DUP_VALUES values (2, 'TEST1');
INSERT INTO DUP_VALUES values (3, 'TEST2');
INSERT INTO DUP_VALUES values (4, 'TEST2');
INSERT INTO DUP_VALUES values (5, 'TEST1');
INSERT INTO DUP_VALUES values (6, 'TEST1');
INSERT INTO DUP_VALUES values (7, 'TEST1');
I want to get
ID NAME
1 TEST1
3 TEST2
I tried with SELECT DISTINCT ID, NAME FROM DUP_VALUES
But, I got all values, because ID is unique.
Use aggregation:
select min(id) as id, name
from dup_values
group by name;

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).

Can I reference this table?

I am trying to show amount paid for each tutor sorted by month and then by tutor id. I have the first part correct and can sort by month but cannot sort by tutor id because it is from a different table.
Here is the script for my tables:
create table match_history
(match_id number(3),
tutor_id number(3),
student_id number(4),
start_date date,
end_date date,
constraint pk_match_history primary key (match_id),
constraint fk1_match_history foreign key (tutor_id) references tutor(tutor_id),
constraint fk2_match_history foreign key (student_id) references student(student_id));
create table tutor_report
(match_id number(3),
month date,
hours number(3),
lessons number(3),
constraint pk_tutor_report primary key (match_id, month),
constraint fk1_tutor_report foreign key (match_id) references match_history(match_id));
insert into tutor values (100, '05-JAN-2017', 'Active');
insert into tutor values (101, '05-JAN-2017', 'Temp Stop');
insert into tutor values (102, '05-JAN-2017', 'Dropped');
insert into tutor values (103, '22-MAY-2017', 'Active');
insert into tutor values (104, '22-MAY-2017', 'Active');
insert into tutor values (105, '22-MAY-2017', 'Temp Stop');
insert into tutor values (106, '22-MAY-2017', 'Active');
insert into student values (3000, 2.3);
insert into student values (3001, 5.6);
insert into student values (3002, 1.3);
insert into student values (3003, 3.3);
insert into student values (3004, 2.7);
insert into student values (3005, 4.8);
insert into student values (3006, 7.8);
insert into student values (3007, 1.5);
insert into match_history values (1, 100, 3000, '10-JAN-2017', null);
insert into match_history values (2, 101, 3001, '15-JAN-2017', '15-MAY-2017');
insert into match_history values (3, 102, 3002, '10-FEB-2017', '01-MAR-2017');
insert into match_history values (4, 106, 3003, '28-MAY-2017', null);
insert into match_history values (5, 103, 3004, '01-JUN-2017', '15-JUN-2017');
insert into match_history values (6, 104, 3005, '01-JUN-2017', '28-JUN-2017');
insert into match_history values (7, 104, 3006, '01-JUN-2017', null);
insert into tutor_report values (1, '01-JUN-2017', 8, 4);
insert into tutor_report values (4, '01-JUN-2017', 8, 6);
insert into tutor_report values (5, '01-JUN-2017', 4, 4);
insert into tutor_report values (4, '01-JUL-2017', 10, 5);
insert into tutor_report values (1, '01-JUL-2017', 4, 2);
This is what I have so far:
Select (hours * 10) as amount paid from tutor_report group by month, tutor_id
however obviously I cannot just say tutor_id at the end.
You can join match_history to get the tutor_id.
But your statement and the query don't match. If you want to sort use ORDER BY.
SELECT tr.hours * 10 amount_paid
FROM tutor_report tr
INNER JOIN match_history mh
ON mh.match_id = tr.match_id
ORDER BY tr.month,
mh.tutor_id;
If you want to aggregate, hours needs to be argument to some aggregation function. Maybe you're after the sum of hours?
SELECT sum(tr.hours) * 10 amount_paid
FROM tutor_report tr
INNER JOIN match_history mh
ON mh.match_id = tr.match_id
GROUP BY tr.month,
mh.tutor_id;
If you are grouping based on columns on two tables,you need to join them on the matching Id and then use group by
Select (hours * 10) as amount paid
from tutor_report a
join match_history b on a. match_id = b.match_id
group by month, tutor_id

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

Update / Merge table with summing values

I have a schema:
http://sqlfiddle.com/#!4/e9917/1
CREATE TABLE test_table (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table VALUES (1000, 1, 100);
INSERT INTO test_table VALUES (1000, 1, 500);
INSERT INTO test_table VALUES (1001, 1, 200);
INSERT INTO test_table VALUES (1001, 2, 300);
INSERT INTO test_table VALUES (1002, 1, 900);
INSERT INTO test_table VALUES (1002, 1, 250);
I want to update the amount field by adding amounts of records which has same (id, period) pair. like after op :
ID| period| amount
1000 1 600
1001 1 200
1001 2 300
1002 1 1150
I Couldn't figure out how :(
EDIT:
In actual case this table is populated by insertion operation from other 2 tables:
CREATE TABLE some_table1(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table1 VALUES (1000, 1, 100);
INSERT INTO some_table1 VALUES (1000, 1, 500);
INSERT INTO some_table1 VALUES (1001, 1, 200);
INSERT INTO some_table1 VALUES (1001, 2, 300);
INSERT INTO some_table1 VALUES (1002, 1, 900);
INSERT INTO some_table1 VALUES (1002, 1, 250);
CREATE TABLE some_table2(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table2 VALUES (1000, 1, 30);
INSERT INTO some_table2 VALUES (1000, 1, 20);
INSERT INTO some_table2 VALUES (1001, 1, 15);
INSERT INTO some_table2 VALUES (1001, 2, 20);
INSERT INTO some_table2 VALUES (1002, 1, 50);
INSERT INTO some_table2 VALUES (1002, 1, 60);
Dublicates occures when two insertions done:
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table1
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table2
new sqlfiddle link: http://sqlfiddle.com/#!4/cd45b/1
May be it can be solved during insertion from two table..
A script like this would do what you want:
CREATE TABLE test_table_summary (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table_summary (id, period, amount)
SELECT id, period, SUM(amount) AS total_amount FROM test_table
GROUP BY id, period;
DELETE FROM test_table;
INSERT INTO test_table (id, period, amount)
SELECT id, period, total_amount FROM test_table_summary;
DROP TABLE test_table_summary;
But you should actually decide if test_table is to have a primary key and the total amount or all the detail data. It's not a good solution to use one table for both.
By what you have added, then I'd say you can use the Oracle MERGE INTO statement:
MERGE INTO test_table t
USING (SELECT id, period, amount FROM some_table1) s
ON (t.id=s.id AND t.period=s.period)
WHEN MATCHED THEN UPDATE SET t.amount=t.amount+s.amount
WHEN NOT MATCHED THEN INSERT (t.id, t.period, t.amount)
VALUES (s.id, s.period, s.amount);
Beware though... this will work only if test_table already has no duplicate id, period rows to begin with. So if your table is already messed up, you still have to reinitialize it properly a first time (and maybe add a unique id, period key to avoid problems in the future).