I have a table to track the Student details and there is another table to track the performance of the student.
+==========================================+
| ID | Department | Date |
+==========================================+
| 001 | English | Jan 3 2017 |
| 001 | English | Feb 24 2017 |
| 001 | Science | Mar 1 2017 |
| 001 | Maths | Mar 2 2017 |
| 001 | Maths | Mar 21 2017 |
| 001 | Maths | Apr 2 2017 |
| 001 | English | Apr 7 2017 |
| 002 | Maths | Feb 1 2017 |
| 002 | Maths | Apr 7 2017 |
| 003 | Maths | Apr 3 2017 |
| 003 | Maths | Apr 7 2017 |
| 004 | Science | Feb 1 2017 |
| 004 | Science | Mar 1 2017 |
| 004 | Maths | Apr 7 2017 |
| 004 | English | Apr 9 2017 |
+==========================================+
Performance table:
+===========================================================================+
| ID | Department | Best score| Avg score | Date |
+===========================================================================+
| 001 | English | 98 | 85 | Jan 30 2017 |
| 001 | English | 89 | 80.2 | Apr 14 2017 |
| 001 | Science | 75 | 79.8 | May 1 2017 |
| 001 | Maths | 88 | 80.2 | Jan 12 2017 |
| 001 | Maths | 79 | 75.6 | Feb 21 2017 |
| 001 | Maths | 90 | 80.5 | Jan 20 2017 |
| 001 | English | 80 | 79.3 | Mar 27 2017 |
| 002 | Maths | 90 | 78.4 | Mar 31 2017 |
| 002 | Maths | 85 | 80.2 | May 7 2017 |
| 003 | Maths | 75 | 79.1 | Apr 30 2017 |
| 003 | Maths | 80 | 80.0 | Feb 7 2017 |
| 004 | Science | 60 | 70.3 | May 1 2017 |
| 004 | Science | 72 | 69.9 | Mar 10 2017 |
| 004 | Maths | 70 | 66.8 | Jan 17 2017 |
| 004 | English | 65 | 65.0 | Mar 29 2017 |
+===========================================================================+
I want to get the most recent performance and average score of the student whenever a department change happens in the student table. Considering student 001, the student's dept changes are
| 001 | English | Jan 3 2017 |
| 001 | Science | Mar 1 2017 |
| 001 | Maths | Apr 2 2017 |
For,
Jan 3 2017, There is no date that is less than the date in the Performance table.
Mar 1 2017, The most recent record in performance table is of date Feb 21 2017
Apr 2 2017, The most recent record in performance table is of date Mar 27 2017
Please help me in doing it.
Take a little pain to explain clearly if my script is wrong
Hope the output that you have explain is correct.Becasue i hv lil doubts about the output.
Most importantly hope you have posted exactly same table structure .
Because of your table structure,lil more window function is use than expected,which may hamper your performance.
It is all together very different and important discussion about your real requirement and what should be table structure and how it should be populated.
Try this script with various sample data and let me know,
declare #StudentDetails table(ID varchar(20)
,Department varchar(20),Dates Date)
insert into #StudentDetails VALUES
('001','English','Jan 3 2017 ')
,('001','English','Feb 24 2017')
,('001','Science','Mar 1 2017 ')
,('001','Maths','Mar 2 2017 ')
,('001','Maths','Mar 21 2017')
,('001','Maths','Apr 2 2017 ')
,('001','English','Apr 7 2017 ')
,('002','Maths','Feb 1 2017 ')
,('002','Maths','Apr 7 2017 ')
,('003','Maths','Apr 3 2017 ')
,('003','Maths','Apr 7 2017 ')
,('004','Science','Feb 1 2017 ')
,('004','Science','Mar 1 2017 ')
,('004','Maths','Apr 7 2017 ')
,('004','English','Apr 9 2017 ')
--select * from #StudentDetails
declare #Performance table( ID varchar(20)
,Department varchar(20),Bestscore float,Avgscore float,PDate date)
insert into #Performance VALUES
('001','English',98,85 ,'Jan 30 2017')
,('001','English',89,80.2 ,'Apr 14 2017')
,('001','Science',75,79.8 ,'May 1 2017 ')
,('001','Maths',88,80.2 ,'Jan 12 2017')
,('001','Maths',79,75.6 ,'Feb 21 2017')
,('001','Maths',90,80.5 ,'Jan 20 2017')
,('001','English',80,79.3 ,'Mar 27 2017')
,('002','Maths',90,78.4 ,'Mar 31 2017')
,('002','Maths',85,80.2 ,'May 7 2017 ')
,('003','Maths',75,79.1 ,'Apr 30 2017')
,('003','Maths',80,80.0 ,'Feb 7 2017 ')
,('004','Science',60,70.3 ,'May 1 2017 ')
,('004','Science',72,69.9 ,'Mar 10 2017')
,('004','Maths',70,66.8 ,'Jan 17 2017')
,('004','English',65,65.0 ,'Mar 29 2017')
--select * from #Performance
--declare #SID varchar(20)='001'
;with CTE as
(
select *
,ROW_NUMBER()over(partition by id order by Dates,Department) rn
from #StudentDetails
--where id=#SID
)
,CTE3 AS(
select c.id, c.Department,c.dates,c.rn,1 rn3
from cte c
where rn=1
union ALL
select c.id, c.Department,c.dates,c.rn
,case when c.Department=c3.Department and c.dates>c3.dates
then cast(c3.rn3 as int)
else cast(c3.rn3+1 as int) end
from cte c
inner join cte3 c3
on c.id=c3.id
where c.rn=c3.rn+1
and c.rn<=7
)
,cte4 AS(
select *,0 rn1 from cte3 where rn=1
union ALL
select * from
(
select * ,ROW_NUMBER()over(PARTITION by id,rn3 order by dates desc) rn1
from cte3
where rn3>1
)t4 where t4.rn1=1
)
select c.id,c.department,c.dates,fn.Avgscore AVGScroe,fn.pdate RecentPDate
from cte4 c
OUTER apply(
select * from
(select p.*,ROW_NUMBER()over( order by pdate desc)rn2
from #Performance P
where c.id=p.id and p.pDate<c.dates)t4
where rn2=1 )fn
order by c.id
Could you try this...
SELECT S.ID,S.DATE,MAX(P.AVG_SCORE),MAX(P.BEST_SCORE)
FROM STUDENT S, PERFORMANCE P
WHERE P.DATE < S.DATE AND P.ID = S.ID
GROUP BY S.ID,S.DATE
Thanks..
I'm using SQL Server 2014. I have a Claims table containing totals of claims made per month in my system:
+-----------+-------------+------------+
| Claim_ID | Claim_Date | Nett_Total |
+-----------+-------------+------------+
| 1 | 31 Jan 2012 | 321454.67 |
| 2 | 29 Feb 2012 | 523542.34 |
| 3 | 31 Mar 2012 | 35344.33 |
| 4 | 30 Apr 2012 | 142355.63 |
| etc. | etc. | etc. |
+-----------+-------------+------------+
For a report I am writing I need to be able to produce a cumulative running total that resets to zero at the start of each fiscal year (in my country this is from March 1 to February 28/29 of the following year).
The report will look similar to the table, with an extra running total column, something like:
+-----------+-------------+------------+---------------+
| Claim_ID | Claim_Date | Nett_Total | Running Total |
+-----------+-------------+------------+---------------+
| 1 | 31 Jan 2012 | 321454.67 | 321454.67 |
| 2 | 29 Feb 2012 | 523542.34 | 844997.01 |
| 3 | 31 Mar 2012 | 35344.33 | 35344.33 | (restart at 0
| 4 | 30 Apr 2012 | 142355.63 | 177699.96 | for new yr)
| etc. | etc. | etc. | |
+-----------+-------------+------------+---------------+
I know windowing functions are very powerful and I've used them in rudimentary ways in the past to get overall sums and averages while avoiding needing to group my resultset rows. I have an intuition that I will need to employ the 'preceding' keyword to get the running total for the current fiscal year each row falls into, but I can't quite grasp how to express the fiscal year as a concept to use in the 'preceding' clause (or if indeed it's possible to use a date range in this way).
Any assistance on the way of "phrasing" the fiscal year for the "preceding" clause will be of enormous help to me, please.
i think you should try this:
/* Create Table*/
CREATE TABLE dbo.Claims (
Claim_ID int
,Claim_Date datetime
,Nett_Total decimal(10,2)
);
/* Insert Testrows*/
INSERT INTO dbo.Claims VALUES
(1, '20120101', 10000)
,(2, '20120202', 10000)
,(3, '20120303', 10000)
,(4, '20120404', 10000)
,(5, '20120505', 10000)
,(6, '20120606', 10000)
,(7, '20120707', 10000)
,(8, '20120808', 10000)
Query the Data:
SELECT Claim_ID, Claim_Date, Nett_Total, SUM(Nett_Total) OVER
(PARTITION BY YEAR(DATEADD(month,-2,Claim_Date)) ORDER BY Claim_ID) AS
[Running Total] FROM dbo.Claims
The Trick: PARTITION BY YEAR(DATEADD(month,-2,Claim_Date))
New Partition by year, but i change the date so it fits your fiscal year.
Output:
Claim_ID |Claim_Date |Nett_Total |Running Total
---------+---------------------------+------------+-------------
1 |2012-01-01 00:00:00.000 |10000.00 |10000.00
2 |2012-02-02 00:00:00.000 |10000.00 |20000.00
3 |2012-03-03 00:00:00.000 |10000.00 |10000.00 <- New partition
4 |2012-04-04 00:00:00.000 |10000.00 |20000.00
5 |2012-05-05 00:00:00.000 |10000.00 |30000.00
6 |2012-06-06 00:00:00.000 |10000.00 |40000.00
7 |2012-07-07 00:00:00.000 |10000.00 |50000.00
8 |2012-08-08 00:00:00.000 |10000.00 |60000.00
I am still learning SQL query. I have a table looks like this:
The Financial_Year_Month_Code consists of the "year" and P01 stands for Period 1. The Calendar Key is just the year month day.
|---------------------------|--------------|--------------------
| Financial_Year_Month_Code | Calendar_Key | Column 3...
|---------------------------|--------------|--------------------
| 1988 P01 | 19870901 |
| ......
| 2013 P01 | 20110901 |
| 2013 P01 | 20110902 |
| 2013 P01 | 20110903 |
| 2013 P01 | ..... |
| 2013 P02 | 20111002 |
| 2013 P02 | 20111003 |
| 2013 P02 | 20111004 |
| MORE...
The result I want to query should look like this:
|----------------------|------------------|--------------------|-----------------|
| Financial_Code_Start | Calendar_Key_Min | Financial_Code_End |Calendar_key_max |
|----------------------|------------------|--------------------|-----------------|
| 2013 P02 | 20110901 | 2014 P01 | 20120930 |
| 2013 P03 | 20111002 | 2014 P02 | 20121029 |
| ....
The original table has a huge list of Financial Year Code from 1988 to 2014. The management would like me to produce a table above to list the financial year code between 2012 and 2014 so they can see the start date and the end date of a rolling 12 month period. Too bad, our developers are all on holiday at the moment so I need help on this one. Thank you very much.
You can group a query by Financial_Year_Month_Code and then calculate aggregates (like MIN and MAX) for each group.
SELECT Financial_Year_Month_Code, MIN(Calendar_Key), MAX(Calendar_Key)
FROM YOUR_TABLE
GROUP BY Financial_Year_Month_Code
I’m about to design a data warehouse and a cube with a product dimension and a sales fact
table. The product dimension is a SCD (type 2).
Lets say the data in the product dimension looks like this the first year:
Name | Product Group | Year
A | A | 2011
B | A | 2011
C | B | 2011
and like this the second year:
Name | Product Group | Year
A | A | 2012
B | B | 2012
C | C | 2012
as you can see some of the products has changed product group between 2011 and 2012.
In the cube I want to ask two types of questions:
The easy one: How much did we sell for in each product group in 2011.
The hard one: How much did we sell for in each product group in 2011 if the products belonged to the product groups they have in 2012.
How would you design the warehouse and the cube do accomplish this?
Thanks!
Ps. I'm using SQL Server 2012
This can be treated as a type 3 SCD. Adding a column [Product Group 2011] allows answering these types of what-if questions.
Name | Product Group | Product Group 2011 | Year
A | A | A | 2012
B | B | A | 2012
C | C | B | 2012
An alternative is to add a durable key to the product dimension and the sales fact.
id | dur_id | Name | Product Group | Year
1 | 1 | A | A | 2012
2 | 2 | B | B | 2012
3 | 3 | C | C | 2012
4 | 1 | A | A | 2012
5 | 2 | B | B | 2012
6 | 3 | C | C | 2012
Then you can join from the SALES fact to the PRODUCT dimesion on the dur_id, just remember to restrict based off of the dimension Year.
For SSAS, you could load in "duplicate" fact rows (i.e. the 2011 and 2012 fact rows associated with 2011, and again associated with 2012) You'd then need to make 2012 the default member for the [Year] attribute hierarchy, and prevent roll-ups that don't specify the year.
I got to great answers over at forums on msdn.
http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/96070b49-954a-456f-9687-3c8afaf74a39
i need a query to find the date based on year, month, day of the week and weekday number. Say for example, if the question is to find the date of 2nd Sunday of January 2010, the answer should be '2010-01-10'.
Inputs are
Yr | Mon | Dy | Dyno
-----------------------
2010 | Jan | Sun | 2
2005 | Jan | Mon | 3
1995 | Feb | Sun | 1
2000 | Feb | Wed | 4
1982 | Mar | Tue | 2
2010 | Mar | Tue | 8
Dyno states dayno
The easiest answer to many date-related questions in SQL is to create a calendar table. In your case, if you create a table with the columns you've already shown, and an extra one with the DATETIME value that you want (call it BaseDate), you can get the value you need with a simple query:
select BaseDate
from dbo.Calendar
where Yr = 2010 and Mon = 'Jan' and Dy = 'Sunday' and Dyno = 2
Of course, your calendar table can have 10, 20 or more columns, depending on what values you find useful for your queries.