Given the following stored procedure, I'd like to be able to shift my input parameters so if the first parameter isn't a valid date, the 2 other parameters that are dates are shifted as the input. I also want to have the current day be used if there are no input parameters to my stored procedure. What is the best way to do it? I'm using SQL Server 2008 r2.
Create PROCEDURE [dbo].[p_qIMO_TEST_2]
#i_InstrumentID VARCHAR(15) = NULL,
#i_DateLow DATETIME = '20090101',
#i_DateHigh DATETIME = '20291231'
AS
IF #i_DateLow IS NULL SET #i_DateLow = CONVERT(DATETIME,CONVERT(DATE,GETDATE()))
IF #i_DateHigh IS NULL SET #i_DateHigh = CONVERT(DATETIME,CONVERT(DATE,GETDATE()))
SELECT * FROM
(
SELECT
out_interface_id,
msg_id,
CAST(xml_msg as XML).value(
'(//InstrumentID)[1]','nvarchar(15)') AS InstrumentID,
msg_type,
xml_msg,
CAST(xml_msg AS XML) as [Quick_XML],
date_received,
status,
last_modified,
environment,
transaction_closed_date
FROM MyTable
WHERE msg_type IN ('ABC','DEF')
AND date_received >= #i_DateLow
AND date_received < DATEADD(DAY,1,#i_DateHigh) -- Need to add 1 to the DateHigh for
-- date range criteria to work properly (>= and <)
) x
WHERE (x.InstrumentID = #i_InstrumentID OR x.InstrumentID = NULL)
ORDER BY date_received DESC
RETURN
GO
Updated for more clarity
Basically, I want it to check if the first argument is a valid date, probably using IsDate()and if it isn't a valid date, then I know it is an InstrumentID. If it is an InstrumentID, I want to check if the next argument is there. If it is there, check if there is a 3rd argument. That would indicate that all 3 arguments are there so I know it is a valid InstrumentID with start and end dates. If there is only a valid first argument, I want it to use the current date for the 2nd and 3rd arguments. I know it's convoluted but that's what I've been asked to do. There is no front end app, so I have to do it in a T-SQL stored procedure.
you can use the ISDATE function to check if the first parameter is a valid date. If it is not use it as a InstrumentId. For second requirement, Make the date parameter defaulted to NULL and in the SP check ISNULL(2ndpara) , ISNULL(3rdPara) That should work.
Related
Write a single query to search between two dates and when To date is not available then it should search greater then first date.
For example: search between two dates, when both from and to dates are available
11-10-2015 to 11-10-2017
My query should also return result when To date is not available
For example: I want to write single query without any if and else
This code works and it is a single statement, as requested.
SELECT * from MyTable WHERE recordingdate BETWEEN COALESCE(#startdate,CAST('01/01/1753 00:00:00.000' AS DATETIME)) AND COALESCE(#enddate,CAST('12/31/9999 23:59:59.997' AS DATETIME))
If the start date is NULL, COALESCE will return the minimum date value, as defined by SQL Server. Otherwise, it returns the start date value sent in.
If the end date is NULL, COALESCE will return the maximum date value, as defined by SQL Server. Otherwise, it returns the end date sent in.
Feel free to turn the COALESCE statements for MIN and MAX possible dates into functions, as SQL Server does not have built-in functions for minimum and maximum possible dates.
Writing your code this way allows you to always execute a BETWEEN.
Try Thie below Logic
DECLARE #FromDt DATE='01/01/2017',#ToDate DATE = NULL
SELECT
*
FROM YourTable
WHERE FromDate > #FromDate
AND
(
#ToDate IS NULL
OR
(
#ToDate IS NOT NULL
AND
ToDate > #ToDate
)
)
declare #dt_from date = '20151011',
#dt_to date = '20171011' -- null
select *
from dbo.your_table
where date_field >= #dt_from and data <= isnull(#dt_to, '99990101');
I'm having problems getting back the data I'd expect from a stored procedure. The procedure is used to both insert and update record, and this determines which parameters are set when called. My example here is assuming the DATE type parameter has the default value of NULL, i.e. they have not been passed into the sp. I have broken the code down into a small section to fix, rather than include the entire procedure code, as follows:
-- these would be sp parameters
declare #CustomerId int = 15
declare #Indicator varchar(5) = 'Yes'
declare #ProjectTypeId tinyint = 1
declare #FutureEffectiveDate as date = null
SELECT
CASE #FutureEffectiveDate
WHEN NULL THEN
CASE #Indicator
WHEN 'Yes' THEN
-- can only be 1, 2 or 3 to return relevant date
CASE #ProjectTypeId
WHEN 1 THEN DI.[NextFormalEffectiveDate]
WHEN 2 THEN DI.[NextInterimEffectiveDate]
WHEN 3 THEN DI.[NextAccountingEffectiveDate]
END
-- data should be NULL if #Indicator not 'Yes'
ELSE NULL
END
ELSE #FutureEffectiveDate
END AS [FutureEffectiveDate]
FROM
[_Staging].[DataImport_2] AS DI
JOIN
[CustomerView] AS CV ON CV.[CustomerNumber] = DI.[BillingInvoiced]
JOIN
[ProjectType] AS PT ON PT.[ProjectType] = DI.[ProjectType]
WHERE
CV.[CustomerID] = #CustomerId AND
PT.[ProjectTypeID] = #ProjectTypeId
So the idea is that, for records where a field contains the text 'Yes', and based on the project type for that record, it selects one of three dates. If the field is not 'Yes' then it should return NULL, ignoring the project type. If the date parameter is NOT null, then it should simply return the parameter passed in. The result is returned as the column 'FutureEffectiveDate'. With the example data I have, I would expect a date to be returned as the relevant field is 'Yes', and the column NextFormalEffectiveDate has a value (as project type is 1).
Oddly enough, if you exclude the outer CASE statement, it works. So the issue is around determining what to do based on the DATE parameter, but i cannot see why the outer CASE statement is breaking the result.
The way you checked #FutureEffectiveDate for NULL in CASE statement is wrong. Here is a small demo
declare #FutureEffectiveDate as date = null
Select Case #FutureEffectiveDate when NULL then 1 else 0 end
The above query will result 0. Because the above CASE statement validates the input expression like #FutureEffectiveDate = NULL which will fail. NULL should be compared using IS operator
Here is the correct way to compare NULL
SELECT CASE
WHEN #FutureEffectiveDate IS NULL THEN
CASE ..
I have a problem with my report from a live query. In my report i have 5 parameters that allow to pick a date range #DateFrom and #DateTo and 3 parameters which should allow to select specific attributes:
#salesid, #batch, #serial
I want to make date range parameters mandatory and that's working without any problems but last 3 parameters: #salesid, #batch, #serial should be optional.
But they do not work as they should. Last 3 parameters should let you type in value which would work as filters. But when I pick date and one of those parameters Im getting the entire value of the query instead of selected values.
In parameters properties I slected "Allow blank value (" ")" option and just in case I defined a default value as blank.
That's how conditions in my query looks like:
where
st.custaccount <> 'number%'
and datepart(year,st.CREATEDDATETIME) >= 2012
and (ita.VENDORCODE like'producer1' or ita.vendorcode like 'producer2')
and st.createddatetime >= #FromDate
and st.createddatetime <= #ToDate
or (st.salesid = #salesid or #salesid is null)
or (itd.INVENTBATCHID = #batch or #batch is null)
or (itd.INVENTSERIALID = #serial or #serial is null)
Theoretically it should work but... Well but in practice it's not.
How to set a condition to get the desired effect? I couldn't find anything helpful so far. If any of you know something useful please give me some clues.
You need to change your final 3 or statements to and statements.
At the moment, your query is essentially checking for data items that match your criteria OR that any of those final three parameters is matched/null. This means that even if you data isn't the date range etc it will still be returned:
where st.custaccount <> 'number%'
and st.CREATEDDATETIME >= '20120101' -- Try not to use functions in your WHERE clause, as this stops indexes from working, making your query less efficient.
and ita.VENDORCODE in('producer1', 'producer2') -- IN has the same effect.
and st.createddatetime between #FromDate and #ToDate -- BETWEEN is an inclusive date range. Equivalent to >= and <=
and (st.salesid = #salesid
or #salesid is null
)
and (itd.INVENTBATCHID = #batch
or #batch is null
)
and (itd.INVENTSERIALID = #serial
or #serial is null
)
I am dealing with legacy Informix data apparently never validated properly upon input.
This means that a DATE field could contain
a proper date (12/25/2000),
a garbage date (02/22/0200),
NULL, or
the Lindbergh baby.
The following works nicely in SQL Server:
SELECT
COUNT(1) AS [Grand Total Count of Bad-Date Records],
COUNT(GOOFYDATE) AS [Count of Just NON-NULL Bad-Date Records],
SUM(IIF(GOOFYDATE IS NULL,1,0)) AS [Count of Just NULL Bad-Date Records]
FROM MyTable
WHERE ISDATE(GOOFYDATE)=0
Everything above adds up.
In Informix,
SELECT COUNT(1)
FROM MyTable
WHERE DATE(GOOFYDATE) IS NULL
gives me the Grand Total, as before. However, the following does, too:
SELECT COUNT(1)
FROM MyTable
WHERE DATE(GOOFYDATE) IS NULL
AND GOOFYDATE IS NULL
How may I implement in Informix my ISDATE goal, as accomplished above in SQL Server?
You can write a stored procedure/function to perform this task, so that it will work exactly like the SQL Server equivalent. Something like:
CREATE FUNCTION informix.isdate(str VARCHAR(50), fmt VARCHAR(50))
RETURNING SMALLINT;
DEFINE d DATE;
ON EXCEPTION IN (-1277,-1267,-1263) -- other errors are possible
RETURN 0;
END EXCEPTION;
LET d = TO_DATE(str, fmt); -- acceptable date if exception not raised
IF d < MDY(1,1,1850) THEN -- dates prior to this are "logically invalid"
RETURN 0;
END IF;
RETURN 1;
END FUNCTION;
Which you can use thus:
-- Sample data
CREATE TEMP TABLE test1 (str VARCHAR(50));
INSERT INTO test1 VALUES ("not a date");
INSERT INTO test1 VALUES ("02/25/2016");
INSERT INTO test1 VALUES ("02/30/2016");
INSERT INTO test1 VALUES ("02/01/0000");
SELECT str, ISDATE(str, "%m/%d/%Y") FROM test1;
str (expression)
not a date 0
02/25/2016 1
02/30/2016 0
02/01/0000 0
4 row(s) retrieved.
SELECT str AS invalid_date
FROM test1
WHERE ISDATE(str, "%m/%d/%Y") = 0;
invalid_date
not a date
02/30/2016
02/01/0000
3 row(s) retrieved.
Depending on how goofy your dates are, you may find other errors crop up. Just adjust the ON EXCEPTION clause accordingly. I've written this function to be as general purpose as possible, but you could code the "accepted" date format into the routine rather than pass it as an argument. (I don't recommend that, though.)
I want to get back two values from the the function and first value assign to one variable and second value assign to another variable write now i get by calling the function two time by passing return type parameter for example #retType 1 then return first value if #retType 2 then return second value
but i need to call fuinction two time but my intension is to call only one time and get two values to two variable is it possible ?...
Stored procedure:
DECLARE #policy_effitive_st DATE -- policy Period Start From
DECLARE #policy_effitive_end DATE -- calculated date
SELECT
#policy_effitive_end = policydatecalc(memberid) --assign first column column1
, #policy_effitive_end = policydatecalc(memberid) --assign second column column2
FROM
member
Function:
CREATE FUNCTION [owner].[policydatecalc]
(#parm1 <datatpe> = <default>)
RETURNS TABLE
AS RETURN
(
DECLARE #col1,#col2 date
--- calulation for dates logic here
SELECT #col1,#col2 )
You need to create a table-valued function like this (see the details of exactly how to define a table-valued function in the official MSDN or Technet documentation - they are really good and extensive!):
CREATE FUNCTION dbo.policydatecalc
(#NumberOfMonths INT = 1)
RETURNS #OutputTbl TABLE (DateValStart DATE, DateValEnd DATE)
AS
BEGIN
INSERT INTO #OutputTbl (DateValStart, DateValEnd)
VALUES (SYSDATETIME(), DATEADD(MONTH, #NumberOfMonths, SYSDATETIME()));
RETURN
END
and then you can call it and assign its values in the stored procedure like this:
CREATE PROCEDURE dbo.SomeProcedure
AS
BEGIN
DECLARE #Start DATE, #End DATE
SELECT
#Start = DateValStart,
#End = DateValEnd
FROM
dbo.policydatecalc(4)
END
The function declaration defines a table type (and a variable of that type) that gets returned - and that's what you'll get back in the stored procedure when you call the function. This is like any other table - you can select from it and assign the values to internal variables in the stored procedure.