SSRS: Parameter population from a dataset - reporting-services

I have a dataset with start dates, end dates, and term codes. The user will enter in an academic year. The academic year will be used to determine the three term codes for that year. I want to use those three codes to select start and end dates for each term, which will go into the main query. I can achieve this by setting up three datasets that will hold the term code, start date, and end date for each term and populating the start and end date parameters from there, but what I want to know is if there is a more dynamic way to achieve this.
Thanks!
Some clarification. I want a way to populate all six parameters from one dataset, not each start and end date getting its own dataset.

I can't be sure of how your data is set up, so I'm going to make a few guesses here. You can return six separate dates by pivoting the Start and End Dates for each Term:
declare #TermCodes table(AcademicYear int,TermCode varchar(50))
insert into #TermCodes
values
(2014,'FL14'),
(2014,'SP14'),
(2014,'SM14')
declare #TermDates table(TermCode varchar(50), StartDate date,EndDate date)
insert into #TermDates
values
('FL14','20140915','20141215'),
('SP14','20150115','20150415'),
('SM14','20150515','20150815')
declare #AcademicYear int
set #AcademicYear = 2014
select
min(StartDate1) StartDate1,
min(EndDate1) EndDate1,
min(StartDate2) StartDate2,
min(EndDate2) EndDate2,
min(StartDate3) StartDate3,
min(EndDate3) EndDate3
from (
select
td.StartDate,
td.EndDate,
'StartDate' + cast(row_number() over(order by td.StartDate) as char(1)) StartDates,
'EndDate' + cast(row_number() over(order by td.StartDate) as char(1)) EndDates
from #TermCodes tc
inner join #TermDates td
on td.TermCode = tc.TermCode
where tc.AcademicYear = #AcademicYear
) t
pivot (
max(StartDate)
for StartDates in(StartDate1,StartDate2,StartDate3)
) sd
pivot (
max(EndDate)
for EndDates in(EndDate1,EndDate2,EndDate3)
) ed

Related

Query giving consecutive dates for following weeks

Is it possible to create a table in SQL, in which 1 column gives the consecutive Sundays. The other column has the upcoming 7 sundays corresponding to each sunday on column1.
Expected output below:
Any help is extremely appreciated.
Try the following:
select date_Sundays,
date_add(date_Sundays,
interval 7*row_number() over (partition by date_sundays order by date_sundays) day)
as nextSundays
from tbl
See a demo.
If you want the whole shebang, something like this:
-- Create Sundays table
CREATE TABLE Sundays (
Date_sundays DATE
);
-- Insert a bunch of Sundays
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = CAST('2022-03-06' AS DATE)
SET #EndDate = CAST('2023-03-05' AS DATE)
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO Sundays (Date_sundays)
SELECT #StartDate
SET #StartDate = DATEADD(#StartDate, INTERVAL 7 DAY)
END
;
-- self JOIN to get next Sundays
SELECT
Sundays.Date_sundays,
Sundays2.Date_sundays AS Date_sundays_next
FROM
Sundays
JOIN Sundays Sundays2
ON Sundays2.Date_sundays BETWEEN
DATEADD(Sundays.Date_sundays, INTERVAL 7 DAY)
AND DATEADD(Sundays.Date_sundays, INTERVAL 49 DAY)
ORDER BY
Sundays.Date_sundays,
Sundays2.Date_sundays
;
You can use a function to generate the list of Sundays and then join to itself to get the future 7 Sundays. When calling the second function in the JOIN, make sure the end date is far enough in the future to encompass the future 7 weeks.
--Function to generate a list of Sundays using a number table.
CREATE FUNCTION fun_GetSundaysList
(
--Need to know the date range for generating these dates.
#StartDate date
, #EndDate date
)
RETURNS TABLE
AS
RETURN
(
--Using a numbers table to generate a list of dates.
--Concept borrowed from this post: https://stackoverflow.com/a/17529962/2452207
SELECT DATEADD(DAY,number+1,#StartDate) [Date]
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY,number+1,#StartDate) < #EndDate
AND DATEPART(WEEKDAY, DATEADD(DAY,number+1,#StartDate)) = 1 --Narrow list to only Sundays.
)
GO
--Select the list of Sundays and JOIN to the same list.
SELECT
s.[Date] as main_sunday
, s1.[Date] as future7_sundays
FROM fun_GetSundaysList ('2022-10-1', '2023-1-1') as s
JOIN fun_GetSundaysList ('2022-10-1', '2023-3-1') as s1
ON s1.[Date] > s.[Date]
AND s1.[Date] < DATEADD(week,8,s.[Date])
ORDER BY s.[Date], s1.[Date]
Sample of list Generated:
Edit: Looking again, I don't like using the master..spt_values for generating the list of dates. The reasoning is that it is an undocumented table, and it only gives you up to 2048 values to use. It is fast. Getting 2048 values from spt_values takes 2ms where generating 10k values using the below joins takes 187ms on my server. Either way, you need to generate a sequence of numbers to help create the dates so here's another way to build the numbers list in the function:
ALTER FUNCTION fun_GetSundaysList
(
--Need to know the date range for generating these dates.
#StartDate date = '10/11/2022'
, #EndDate date = '1/1/2023'
)
RETURNS TABLE
AS
RETURN
(
WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
, y as (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as number
FROM x ones, x tens, x hundreds, x thousands
--ORDER BY 1
)
--Using a numbers table.
SELECT DATEADD(DAY,number+1,#StartDate) [Date]
FROM y
WHERE DATEADD(DAY,number+1,#StartDate) < #EndDate
AND DATEPART(WEEKDAY, DATEADD(DAY,number+1,#StartDate)) = 1
)

MySQL finding MAX of a given field and returning the entire row

Introduction
Hi,
I have a weather station that records the current weather every half an hour.
Among other sensors, it has a thermometer. It is the subject in this enquiry.
I have summarized the fields of my table, but please be aware that HiTemp field stores the maximum temperature.
Situation
Given the following table structure in a SQL query
CREATE TABLE weather (
Id INT AUTO_INCREMENT PRIMARY KEY,
HiTemp FLOAT,
Date VARCHAR(8),
Time VARCHAR(5),
Epoch BIGINT
);
Note that HiTemp is stored in celsius degrees, Date follows dd/mm/YY format and Time is stored in CET (GMT+1) timezone
Therefore, a sample record would be..
1, 19, "13/12/19", "13:00", 1576238400
My goal is to sort through the records and find the maximum value of HiTemp along its other fields for every year in the table.
To find unique years a simple substring on Date works fine
SELECT SUBSTR(Date, -2) AS Year FROM weather GROUP BY Year;
I was thinking to use a PROCEDURE (function) to be able to use some kind of loop to go over the years
This query right here is the closest to my goal I have been able to figure out on my own
SELECT MAX(HiTemp) MaxTemp, SUBSTR(Date, -2) Year, Date, Time FROM weather GROUP BY Year;
Problem here is that as far as I know MAX is a group function and the other selected fields are irrelevant to its value
Nevertheless, the output of this query would have a format like the following
40.1, 19, "28/06/19", "17:00"
37.5, 18, "04/08/18", "14:00"
35.5, 17, "05/08/17", "15:30"
Note that these records are correct in the sense that the resulting selected fields belong to the very same record (they were handpicked)
Any ideas? Subqueries, Joins, Procedures.. Any insight on this is very much appreciated, I'm pretty lost at this point.
Thanks.
You could use a query with a subquery for max temp group by year
select * from weather w
INNER JOIN (
select MAX(HiTemp) MaxTemp, SUBSTR(Date, -2) Year
FROM weather GROUP BY Year
) t on t.MaxTemp = w.HiTemp and t.year = SUBSTR(w.Date, -2)
or
select w.HiTemp, t.Year, w.date, w.time from weather w
INNER JOIN (
select MAX(HiTemp) MaxTemp, SUBSTR(Date, -2) Year
FROM weather GROUP BY Year
) t on t.MaxTemp = w.HiTemp and t.year = SUBSTR(w.Date, -2) Year

SSRS - How do I format SQL data to generate line chart of time series?

I have a table that is set up like
SELECT [EntryDate] --Date
,[StoreId] --Nvarchar
,[PassFailElement] --Int, 1 or 0
And the SSRS report is set up for the user to input #StartDate and #EndDate to bookend the [EntryDate]s they want to see.
Is there a way to create a line graph that shows the values for [PassFailElement] from #StartDate to #EndDate as the first series, DateAdd(DateInterval.Year,-1,#StartDate) to DateAdd(DateInterval.Year,-1,#EndDate) for the second series, and then two years back for the third series?
I'm sure there are a million more elegant ways to do this but here is how I might approach it...
The following is based on the Microsoft supplied NorthWind database so you can recreate it if you really want to...
I've set the actual start and end date values in here but you can comment out the first few lines and then your SSRS parameters will be applied.
So to start with a took the orders table as it had some dates in and joined to some basic order data just so I could see the results looked OK, most of the columns are not used.
My dataset looks like this...
SET DATEFORMAT YMD
DECLARE #startDate date = '1998/04/01'
DECLARE #endDate date = '1998/07/30'
SELECT
e.EmployeeID, e.FirstName, e.LastName, e.Title
, o.OrderID, o.OrderDate
, c.CustomerID, c.CompanyName
, CASE
WHEN (OrderDate between #startDate and #endDate ) THEN 'This Year'
WHEN (OrderDate between dateadd(YYYY,-1,#startDate) and dateadd(YYYY,-1,#endDate )) THEN 'Last Year'
WHEN (OrderDate between dateadd(YYYY,-2,#startDate) and dateadd(YYYY,-2,#endDate )) THEN '2 Years ago'
END as YearGroup
, MONTH(OrderDate) AS OrderMonth
, Day(OrderDate) AS OrderDay
FROM Employees e
join Orders o on e.EmployeeID = o.EmployeeID
join Customers c on o.CustomerID = c.CustomerID
WHERE
(OrderDate between #startDate and #endDate ) OR
(OrderDate between dateadd(YYYY,-1,#startDate) and dateadd(YYYY,-1,#endDate )) OR
(OrderDate between dateadd(YYYY,-2,#startDate) and dateadd(YYYY,-2,#endDate ))
The Case statement in the SELECT clause checks to see if the dates fall into one of three groups, either
between the start and end dates supplied
between the same date range but minus a year
between the same date range but minus two years
The computed OrderMonth and OrderDay are there as I assume you will want to 'stack' the lines so say, 1 June, across all three groups is in the same horizontal position on the chart. ** See notes later for changing this.
The WHERE clause does similar tests to make sure we only return data from the ranges we need.
All I did them was simply add a line chart and set
the Series Groups to the [YearGroup] field
the [OrderMonth] and [OrderDay] to the CategoryGroup
and (for no other reason than I didn't have much else to display) I used the sum of OrderID as the values.
** if you want to represent the time range as one continuous time, then remove the OrderMonth and OrderDay from the category groups and replace with OrderDate
The resulting chart looked awful but that was just down to the data.
I would create a couple of Calculated Fields in your dataset to break up the data and add them to the chart.
The first would be a field that determines which year the data is in - Current, Previous or the Prior. Maybe just 0, 1 or 2? This field would be used as your chart series. Call it ENTRY_YEAR.
The second would be a date field with the years all set to the current year. You could just add the integer from the first field. This will normalize all your data to a single year timeline. You won't actually use the year - that's just to separate the data at the year break.
=DATEADD("y", ENTRY_YEAR, Fields!EntryDate.Value)

Finding the area available for the date range

Suppose you have a room which is 100sqft and you want to rent it from 1st Aug to 31st Aug.
Bookings Table schema
startdate|enddate|area|storageid
you have following bookings
06-Aug|25-Aug|50|'abc'
05-Aug|11-Aug|40|'xyz'
18-Aug|23-Aug|30|'pqr'
13-Aug|16-Aug|10|'qwe'
Now somebody requests for booking from 08-Aug to 20-Aug. For this date range the maximum area available is 10sqft (Since, for dates 8,9,10 and 11 Aug only 10sq ft is available.)
How would you create an efficient SQL query to get this? Right now I have very messy and inefficient query which gives wrong results for some cases. I am not posting the query because It is so messy that I can't explain it myself.
I don't necessarily want to solve it using SQL only. If there is an algorithm that can solve it efficiently I would extract all the data from database.
Someone removed SQL Server, but here is the algorithm:
DECLARE #startDate date = '2016-08-09';
DECLARE #endDate date = '2016-08-20';
DECLARE #totalArea decimal(19,2) = 100;
WITH Src AS --Your source table
(
SELECT * FROM (VALUES
('2016-08-06', '2016-08-25', 50, 'abc'),
('2016-08-05', '2016-08-11', 40, 'xyz'),
('2016-08-18','2016-08-23',30,'pqr'),
('2016-08-13','2016-08-16',10,'qwe')
)T(startdate, enddate, area, storageid)
), Nums AS --Numbers table 0..N, N must be greater than ranges calculated
(
SELECT 0 N
UNION ALL
SELECT N+1 N FROM Nums
WHERE N<DATEDIFF(DAY,#startDate,#endDate)
) --Query
--You can use total-maxUsed from range of days
SELECT #totalArea-MAX(Used) FROM
(
--Group by day, sum all used areas
SELECT MidDate, SUM(Used) Used FROM
(
--Join table with numbers, split every day, if room used, return area
SELECT DATEADD(DAY, N, #startDate) MidDate, CASE WHEN DATEADD(DAY, N, #startDate) BETWEEN startDate AND endDate THEN area END Used
FROM Src
CROSS APPLY Nums
) T
GROUP BY MidDate
) T

Aggregate daily data to weekly level in SQL: Tuesday to Monday being a week

I have a daily level Sales data and I want to aggregate it to weekly level in SQL server.
Start of any week should be Tuesday and End being Monday respectively
Please help
You should post a bit more about what you've tried. Maybe give us some sample code and problems you are having. That being said please see below. Without seeing your solutions specifics there's a lot of different approaches to this.
SQL FIDDLE
SET DATEFIRST 2;
DECLARE #SalesData TABLE (ID INT PRIMARY KEY IDENTITY(1,1), SalesDate DATETIME, Price MONEY)
INSERT INTO #SalesData (SalesDate,Price) VALUES
('1/1/2013',12.00),
('1/2/2013',14.00),
('1/3/2013',11.28),
('5/3/2013',11.64),
('5/3/2013',18.00)
;WITH
SalesInfo AS
(
SELECT sd.id,
YEAR(sd.SalesDate) AS TheYear,
DATEPART(week,sd.SalesDate) AS TheWeek
FROM #SalesData sd
)
SELECT SI.TheYear,
SI.TheWeek,
SUM(SD.Price) AS TotalForWeek
FROM #SalesData AS SD
INNER JOIN SalesInfo AS SI ON (SD.ID = SI.ID)
GROUP BY SI.TheYear,SI.TheWeek
SET DATEFIRST 7
DATEFIRST MSDN