Using a Lookup function in a Parameter Default - sql

Goal: To provide dynamic date calculations for SSRS Parameters to be used in scheduling.
I have a report containing two date parameters, DateRangeBegin and DateRangeEnd. The problem we are running into is that users want to schedule this report for a date range like "Month to Date", "Year to Date", "Last Week", etc. When a user goes to schedule the report, they can only provide static dates for these two parameters.
The idea I had was to create a dataset that will calculate these values and be referenced in another parameter called DynamicDate. The user would then select "Yesterday", from the DynamicDate parameter, and the DateRangeBegin and DateRangeEnd parameters would get updated with the calculated values from the dataset.
The dataset would be something like this:
Select
2 as DateCalcId,
'Yesterday' as DateCalcDescription,
CONVERT(VARCHAR, DATEADD(DAY,-1,GETDATE()), 101) as DateCalcBegin,
CONVERT(VARCHAR, DATEADD(DAY,-1,GETDATE()), 101) as DateCalcEnd
UNION ALL
Select
1 as DateCalcId,
'Today' as DateCalcDescription,
CONVERT(VARCHAR, DATEADD(DAY,0,GETDATE()), 101) as DateCalcBegin,
CONVERT(VARCHAR, DATEADD(DAY,0,GETDATE()), 101) as DateCalcEnd
UNION ALL
Select
3 as DateCalcId,
'Month to Date' as DateCalcDescription,
CONVERT(VARCHAR,(CONVERT(datetime, CONVERT(VARCHAR, Year(GetDate())) + '-' + Convert(Varchar,Month(GetDate())) + '-01')), 101) as DateCalcBegin,
CONVERT(VARCHAR, DATEADD(DAY,0,GETDATE()), 101) as DateCalcEnd
order by
DateCalcId
I think the function I'm wanting to use is the Lookup() function in the date parameters for their default values, but I'm having a little trouble with the syntax. So far I have:
=Lookup(Parameters!DynamicDate.Value, Fields!DateCalcId.Value, Fields!DateCalcBegin.Value, "CalculatedDates")
But I'm getting this error:
A Value expression used for the report parameter 'DateRangeBegin'
refers to a field. Fields cannot be used in report parameter
expressions.
Does anyone know how to get this working? Or is there another way people have done this?

So I think I've come up with a pretty good solution that fits my requirements.
I really like the idea of having these dynamic date range pairs being calculated in a SQL Dataset because they can be reused across multiple reports, don't require a custom dll to be created, and the pair can be calculated in a single record.
So the solution is to have a single stored procedure that takes a nullable parameter, where passing in null returns the entire set, but passing in the DateCalcId will return a single record that can then be attributed to the range beginning and end parameters.
So the entire dataset would populate the Available Values for the first parameter (#DynamicDate), where the Value field is the "DateCalcId" column, and the Label field is the "DateCalcDescription" column.
Then the date range parameters default values would be tied to the single result dataset using the #DynamicDate value as the input to the stored procedure.
This allows the user to select the Dynamic Date and the date range parameters are defaulted to the calculated dates, and the user is able to overwrite these dates if they desire.
If the dates should always be calculated based on the value selected, then the date parameter Available values can be set to the single result dataset as well.
Here is the stored procedure:
Create PROCEDURE [CNF].[RptCalculatedDateRanges]
#DynamicDateId int = null
AS
BEGIN
SET NOCOUNT ON;
Declare #Today datetime = convert(varchar,getdate(),101)
Select
*
from
(
Select
2 as DynamicDateId,
'Yesterday' as DynamicDateDescription,
DATEADD(DAY,-1,#Today) as DynamicDateBegin,
DATEADD(DAY,-1,#Today) as DynamicDateEnd
UNION ALL
Select
1 as DynamicDateId,
'Today' as DynamicDateDescription,
#Today as DynamicDateBegin,
#Today as DynamicDateEnd
UNION ALL
Select
3 as DynamicDateId,
'Month to Date' as DynamicDateDescription,
CONVERT(VARCHAR,(CONVERT(datetime, CONVERT(VARCHAR, Year(#Today)) + '-' + Convert(Varchar,Month(#Today)) + '-01')), 101) as DynamicDateBegin,
#Today as DynamicDateEnd
) D
where
#DynamicDateId = D.DynamicDateId or
#DynamicDateId is null
order by
DynamicDateId
END

You don't to use a dataset, you can just use the Default expression to calculate the parameter date value using VBA. For example, DateRangeEnd for the following dates would be:
Yesterday:
=DateAdd(DateInterval.Day, -1, Today)
End of Last Month:
=DateAdd(DateInterval.Day, -1, DateAdd(DateInterval.Day, 1-Day(Today), Today))
So you have a SWITCH statement based on your DynamicDate parameter:
=Switch(Parameters!DynamicDate.Value = 1, Today, Parameters!DynamicDate.Value = 2, DateAdd(DateInterval.Day, -1, Today))
and so on for all your date range choices.

Related

How to split dash-separated values in SQL Server

I have a date saved in an nvarchar type and I want to split the day, month and year into separate nvarchar variables (that means three variables). The date looks as follows: exposure_date ='2018-12-04' and the format is yyyy-dd-mm
any help please?
My whole project is stuck on this.
The "correct" answer here is to fix your datatype. When storing data always choose an appropriate data type for the data you're storing. For a date (with no time part) then the correct datatype is date. if you're storing numerical data, then use a numerical datatype, such as int or decimal. (n)varchar is not a one size fits all datatype and using it to store data that has a data type designed for it is almost always a bad choice. I'm storing the data as an (n)varchar because I need it in a specific format is never an excuse; have your presentation layer handle to display format, not your RDBMS.
The first step, therefore would be to change your string representation yyyy-dd-MM of a date to the ISO format yyyyMMdd by doing:
UPDATE YourTable
SET exposure_date = LEFT(exposure_date,4) + RIGHT(exposure_date,2) + SUBSTRING(exposure_date,6,2);
Now you have a unambiguous representation, you can change the data type of your column without concerns of incorrect implicit casts or error:
ALTER YourTable ALTER COLUMN exposure_date date;
Then, finally, you can treat your data as what it is, a date, and use the DATEPART function:
SELECT DATEPART(YEAR,exposure_date) AS Exposure_Year,
DATEPART(MONTH,exposure_date) AS Exposure_Month,
DATEPART(DAY,exposure_date) AS Exposure_Day
FROM YourTable;
You can also try the following
Declare #myDate date
select #myDate= Cast(substring('2011-29-12', 1, 4)
+ '-' + substring('2011-29-12', 9, 2)
+ '-' + substring('2011-29-12', 6, 2)
as Date) --YYYY-MM-DD
Select #myDate as DateTime,
datename(day,#myDate) as Date,
month(#myDate) as Month,
datename(year,#myDate) as Year,
Datename(weekday,#myDate) as DayName
The output is as shown below
DateTime Date Month Year DayName
--------------------------------------------
2011-29-12 29 12 2011 Thursday
You can find the live demo here
You can try below -
select concat(cast(year(cast('2018-12-04' as date)) as varchar(4)),'-',
cast(month(cast('2018-12-04' as date)) as varchar(2)), '-',
cast(day(cast('2018-12-04' as date)) as varchar(2)))
from tablename
If you have fixed format, then you could use this simple query with substring method:
select substring(dt, 1, 4) + '-' +
substring(dt, 9, 2) + '-' +
substring(dt, 6, 2) [YYYY-MM-DD]
from (values ('2018-31-12')) tbl(dt)
Let's go directly to the main issue, which is you are using the wrong datatype to store dates, you should store them as DATE, the datatypes are there for a reason and you need to choose a proper one for your column.
So, you need to ALTER your table and change the column datatype to DATE instead of NVARCHAR datatype.
ALTER <Table Name Here>
ALTER COLUMN <Column Name Here> DATE;
Then all things will easy, you just run the following query to get the desired output
SELECT YEAR(<Column Name Here>) TheYear,
MONTH(<Column Name Here>) TheMonth,
DAY(<Column Name Here>) TheDay
FROM <Table Name Here>
Which is the right and the best solution.
You can also (if you are not going to alter your table) do as
CREATE TABLE Dates(
StrDate NVARCHAR(10)
);
INSERT INTO Dates VALUES
(N'2018-12-04'),
(N'Invalid');
SELECT LEFT(StrDate, 4) StrYear,
SUBSTRING(StrDate, 6, 2) StrMonth,
RIGHT(StrDate, 2) StrDay
FROM Dates;
OR
SELECT YEAR(StrDate) StrYear,
MONTH(StrDate) StrMonth,
DAY(StrDate) StrDay
FROM (
SELECT TRY_CAST(StrDate AS DATE) StrDate
FROM Dates
)T

Find data with specific date and month only

I am trying to find a data with specific where clause of date and month but I am receiving an error can anyone help me with this?
select *
from my_data
where date BETWEEN '11-20' AND '12-15'
MS SQL Server Management Studio
I am receving an error
Conversion failed when converting date and/or time from character string
Most databases support functions to extract components of dates. So, one way of doing what you want is to convert the values to numbers and make a comparison like this:
where month(date) * 100 + day(date) between 1120 and 1215
The functions for extracting date parts differ by database, so your database might have somewhat different methods for doing this.
The conversion is failing because you are not specifying a year. If you were to specify '11-20-2015' your query would work just insert whatever year you need.
SELECT *
FROM my_data
WHERE date BETWEEN '11-20-2015' AND '12-15-2015'
Alternatively if you wanted data from that range of dates for multiple years I would use a while loop to insert information in a # table then read from that table, depending on the amount of data this could be quick or sloooowww here is an example.
DECLARE #mindatestart date, #mindateend date, #maxdatestart date
SET #mindatestart = '11-20-2010'
SET #mindateend = '12-15-2010'
SET #maxdatestart = '11-20-2015'
SELECT top 0 *, year = ' '
INTO #mydata
FROM my_data
WHILE #mindatestart < #maxdatestart
BEGIN
INSERT INTO #mydata
SELECT *, YEAR(#mindatestart)
FROM my_data
where date between #mindatestart and #mindateend
SET #mindatestart = DATEADD(Year, 1, #mindatestart)
SET #mindateend = DATEADD(Year, 1, #mindateend)
END
This will loop and insert the data from 2010-2015 for those date ranges and add a extra column on the end so you can call the data and order by year if you want like this
SELECT * FROM #mydata order by YEAR
Hopefully some part of this helps!
FROM THE COMMENT BELOW
SELECT *
FROM my_data
WHERE DAY(RIGHT(date, 5)) between DAY(11-20) and DAY(12-15)
The reason '11-20' doesn't work is because its a character string which is why you have to input it between ' ' What the Month() function does is take whatever you put between the () and convert it to an integer. Which is why you're not getting anything back using the method in the first answer, the '-Year' from the table date field is being added into the numeric value where your value is just being converted from 11-20 you can see by using these queries
SELECT MONTH(11-20) --Returns 12
SELECT MONTH(11-20-2015) -- Returns 6
SELECT MONTH(11-20-2014) -- Returns 6
Using RIGHT(Date, 5) you only get Month-day, then you date the day value of that so DAY(RIGHT(DATE, 5) and you should get something that in theory should fall within those date ranges despite the year. However I'm not sure how accurate the data will be, and its a lot of work just to not add an additional 8 characters in your original query.
Since you only care about month and day, but not year, you need to use DATEPART to split up the date. Try this:
select *
from my_data
WHERE 1=1
AND (DATEPART(m, date) >= 11 AND DATEPART(d,date) >= 20)
AND (DATEPART(m, date) <= 12 AND DATEPART(d,date) <= 15)

SQL Server: use parameter instead of GETDATE()

I have a stored procedure that uses selects like the following which works fine so far.
In this case for example it selects all records with a date from the previous month, i.e. March 2014 (column: dateEsc, formatted as nvarchar(20), example date: 2014-03-25).
My Select (example):
SELECT COUNT(*) AS groupCount
FROM Log_Esc
WHERE
CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -1, GETDATE()), 112) + '01', 112)
How do I have to change this if instead of the current Date (GETDATE()) I want to use a variable date input as the reference.
This input would be any date and is formatted as nvarchar(20) as well, example: 2014-04-03.
So instead of calculating the previous month compared to the current month from GETDATE() I would like to calculate the same from the variable date input.
Many thanks for any help with this, Tim.
First of all I think this query is better than the one you have:
SELECT COUNT(*) AS groupCount
FROM Log_Esc
WHERE DATE >= dateadd(month,datediff(month,0,dateadd(month,GETDATE(),-1)),0)
AND DATE < dateadd(month,datediff(month,0,GETDATE()),0)
If there is an index on the DATE field this can do a seek.
If you have a parameter #indate defined as date or datetime then this will work
SELECT COUNT(*) AS groupCount
FROM Log_Esc
WHERE DATE >= dateadd(month,datediff(month,0,dateadd(month,#indate,-1)),0)
AND DATE < dateadd(month,datediff(month,0,#indate),0)
See this question for more information on flooring a date to a month: Floor a date in SQL server
So what you want is a parameter:
Specifying Parameters in a Stored Procedure
Parameters allow you to pass user input to modify output.
An example
CREATE PROCEDURE dbo.Param1
#param int
AS
BEGIN
select 7 *#param as Value
END
EXEC dbo.Param1 5 -- 7 *5
EXEC dbo.Param1 -10 -- 7 * -10
Perhaps this'll give you some creative ideas for how you might implement parameters to accomplish your group count.

finding data lying between a specific date range in sql

I want to find records from my database which lie between any user input date range(say between 10/2/2008 to 26/9/2024). I tried using
SELECT NAME
,TYPE
,COMP_NAME
,BATCH_NO
,SHELF
,MFG_DATE
,EXP_DATE
,QTY
,VAT
,MRP
FROM STOCK_LOCAL
WHERE
convert(VARCHAR(20), EXP_DATE, 103)
BETWEEN convert(VARCHAR(20), #MEDICINEEXP_DATE, 103)
AND convert(VARCHAR(20), #MEDICINEEXPDATE, 103)
but with this query i need to enter perfect date range which is available in my database, it is not giving me data lying in between any date entered.
Thanks in advance
Since it is a poolr designed schema there isnt going to be any decent/Efficient solution for this.
In sql server if you are storing Date or Date & Time data. Use the Data or DATETIME datatypes for your columns.
In your case you are trying to compare a string with passed date. and even when you tried to convert the string (Date) into date datatype you didnt do it correctly.
My suggestion would be Add new columns to your table with Date datatype and update these columns with existing date/string values.
For now you can convert the Date(string) into date datatype using the following code.
DECLARE #MEDICINEEXP_DATE DATE = 'SomeValue1'
DECLARE #MEDICINEEXPDATE DATE = 'SomeValue1'
SELECT query....
FROM TableName
WHERE
CAST(
RIGHT(EXP_DATE, 4)
+SUBSTRING(EXP_DATE,CHARINDEX('/',EXP_DATE)+1,2)
+LEFT(EXP_DATE,2)
AS DATE) >= #MEDICINEEXP_DATE
AND CAST(
RIGHT(EXP_DATE, 4)
+SUBSTRING(EXP_DATE,CHARINDEX('/',EXP_DATE)+1,2)
+LEFT(EXP_DATE,2)
AS DATE) <= #MEDICINEEXPDATE
Note
This solution will get you the expected results but very inefficient method. It will not make use of any indexses on your EXP_DATE Column even if you have a very buffed up index on that column.

Converting m/d/y strings to datetime yields conversion error

Here is the code I'm using:
SELECT SalesItemPK
,FieldName
,Value /*Convert date to the first of the selected month*/
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN(
1425
,1225
,1556
,1589
,1599
,1588
,1590)
AND FieldName = 'Estimated Ship Date'
AND CONVERT(DATETIME, Value) >= CONVERT(DATETIME, '1/1/2010')
(I'm selecting just those PKs because those are all the rows in the query.)
This is the error I receive:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value
Below is a sample of the data returned from my view. The final solution actually converts the values to the first of their respective months. But an error is thrown either way.
When I remove the WHERE, it works fine. So there's something strange going on there I can't seem to figure out so far. Any ideas?
Odds are, either the date is being interpreted as d/m/y (and the first row fails because there is no 18th month), or you have a piece of data in there where the first part (month) is > 12.
To find offending rows:
SELECT Value FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND ISDATE(Value) = 0;
(And if you find offending rows, obviously, fix them.)
You can also make sure the values are interpreted as m/d/y (and won't fail on other garbage in the column) using:
SELECT SalesItemPK, FieldName, Value,
FirstOfMonth = CASE WHEN ISDATE(Value) = 1 THEN
DATEADD(DAY,1-DAY(CONVERT(DATETIME,Value,101)),CONVERT(DATETIME,Value,101)) END
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND FieldName = 'Estimated Ship Date'
AND CASE WHEN ISDATE(Value) = 1 THEN CONVERT(DATETIME, Value, 101)
ELSE NULL END >= '20100101';
Also note that just because you perform a WHERE clause on the PK values, does not mean SQL Server has to evaluate that condition first. It could try to convert every row in the view (heck, every row in the source table) to a DATETIME first. Which is why I also added a CASE expression to the SELECT list, just in case. No pun intended. I also offered my suggestion on how to calculate the first of the month easily (a lot of people tend to do really strange things, like convert to string).
Do you have any idea how much simpler this query would be if the view exposed a separate column as datetime, e.g.
, DateValue = CASE WHEN ISDATE(Value) = 1 THEN CONVERT(DATETIME, Value, 101)
Then the query could be:
SELECT SalesItemPK, FieldName, DateValue,
FirstOfMonth = DATEADD(DAY, 1-DAY(DateValue), DateValue)
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND DateValue >= '20100101';
In fact the view could also expose the FirstOfMonth calculation for you too.
These are some of the many, many, many reasons why you should never, ever, ever store date/time data as strings. At the very least, change the view to present these strings as a completely language-, dateformat- and region-neutral string (yyyymmdd) instead of mm/dd/yyyy.
Its probably one of your date values is not in correct format. Try the following query to find list of values that cant be converted as date.
select value from [Oasis].[dbo].[vw_SALES_SalesItemDetails] where isdate(value) = 0