Adding a default value to optional parameter of stored proce - tsql

I want to have a default value for my SQL Server 2008 stored proc as below:
Create Process sp_Transactions1
#earliestDate varchar(12)= CAST(DATEPART(YEAR,DATEADD(m,-3, getdate())) AS VARCHAR(4))  + RIGHT('00' + CAST(DATEPART(mm, DATEADD(m,-2, getdate())) AS varchar(2)), 2)+ '01'
As
But it won't compile
Is this not possible?

As Kritner said above, the default value of parameters can be only a constant.
However, if the NULL value does not have another meaning in this context, you can use something like this:
CREATE PROCEDURE sp_Transactions1
#earliestDate date=NULL
AS
IF #earliestDate IS NULL
SET #earliestDate=CONVERT(DATE,
STR(YEAR(DATEADD(m,-3, getdate())),4)
+RIGHT('0'+CONVERT(VARCHAR(2),MONTH(DATEADD(m,-2, getdate()))),2)
+'01'
)
--...

Related

SQL RIGHT function not working as expected

I'm trying to extract the month number from a date as a left padded string with 0's.
So, for example, from '2018-01-31' I want the string '01'.
Currently I have this:
SELECT RIGHT('0' + CAST(MONTH('2018-01-31') AS CHAR(2)), 2)
Which is returning '1' but I would have expected it to return '01' because I've provided the second argument to RIGHT as 2.
Could someone explain why this isn't working as I think it should?
You need to change CHAR to VARCHAR:
SELECT RIGHT('0' + CAST(MONTH('2018-01-31') AS VARCHAR(2)), 2)
db<>fiddle demo
CHAR(2) is blank padded so you get RIGHT('01 ',2) which is '1 '.
You could use FORMAT instead, when you first cast the string to a DATE type.
SELECT FORMAT(CAST('2018-01-31' as DATE),'MM')
As for why that SQL with the right didn't work?
Try this SQL and notice the difference (the extra space):
SELECT quotename('0' + CAST(1 AS CHAR(2))), quotename('0' + CAST(1 AS VARCHAR(2)))

Unable to use variable in DATEADD(#pinterval, #pinterval, #DayPlus)

DECLARE #pinterval INT = 1, #DayPlus DATETIME = '2016-07-01', #datepart VARCHAR(20) = 'MONTH'
SET #DayPlus = DATEADD(#datepart, #pinterval, #DayPlus)
SELECT #DayPlus
Do we have any alternative to accomplish task ? I have to do it in loop so I can't define it every time based on interval value. Only date part is not acceptable as variable because if I use as
DATEADD(MONTH, #pinterval, #DayPlus)
then it's working fine. Not sure but I can understand the issue but I am seeking for the quick solution. I have visited the web but didn't get exact solution.
It's not possible to substitute a variable for the first argument to DATEADD1, since what is wanted here is a name, not a string.
About the best you can do is a CASE expression:
SET #DayPlus =
CASE #datepart
WHEN 'MONTH' THEN DATEADD(MONTH, #pinterval, #DayPlus)
WHEN 'YEAR' THEN DATEADD(YEAR, #pinterval, #DayPlus)
WHEN 'DAY' THEN DATEADD(DAY, #pinterval, #DayPlus)
--TODO - add all parts you might wish to use
END
1This is even stated in the documentation:
User-defined variable equivalents are not valid.
if this is only the way then I have to repeat this for more than 10times
No, use CROSS APPLY
#Shnugo it sounds good, can you please help me by placing the complete code as an answer. Please !!
About CROSS APPLY: generate something like a variable dynamically
CREATE TABLE dbo.Test(ID INT, SomeDate DATE);
GO
INSERT INTO dbo.Test VALUES(1,{d'2017-01-01'}),(2,{d'2017-02-02'})
GO
DECLARE #Intervall VARCHAR(100)='DAY';
DECLARE #Count INT=1
SELECT dbo.Test.*
,t.AddedDate
FROM dbo.Test
CROSS APPLY(SELECT CASE #Intervall WHEN 'MONTH' THEN DATEADD(MONTH,#Count,SomeDate)
WHEN 'DAY' THEN DATEADD(DAY,#Count,SomeDate)
ELSE SomeDate END AS AddedDate) AS t;
GO
DROP TABLE dbo.Test;
You could use dynamic SQL:
DECLARE #pinterval INT = 1,
#DayPlus DATETIME = '2016-07-01',
#datepart NVARCHAR(20) = 'MONTH'
DECLARE #sql NVARCHAR(MAX) = N'SET #DayPlus = DATEADD('+#datepart+', #pinterval, #DayPlus)',
#params NVARCHAR(MAX) = N'#DayPlus DATETIME OUTPUT, #pinterval INT'
EXEC sp_executesql #sql, #params, #pinterval = #pinterval, #DayPlus = #DayPlus OUTPUT
SELECT #DayPlus
sp_executesql is used for 2 reasons:
to minimize SQL injections risk, it will not eliminate it because of #datepart
it will make sure your dynamic query's plan is going to be cached - which might be beneficial with simple queries (where query time vs compilation time matters)

Getting a value from stored procedure within a stored procedure

I have a stored procedure which returns an XML file. At the moment some calculations are done in XSL but I would like to do these within the database using another stored procedure. (adding the result of that calculation to the XML)
ALTER PROCEDURE [dbo].[app_Get_Phone_And_Tariffs]
-- Add the parameters for the stored procedure here
#phone nvarchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT
PB.UID as '#phoneid',
PB.Short_Title as '#title',
PB.Description as '#desc',
PB.Camera as '#camera',
PB.Storage as '#storage',
PB.Screen_Size as '#screensize',
PB.OS as '#os',
PB.Processor as '#chip',
PB.Image1 as '#image',
PB.Trade_Price as '#tradeprice',
(SELECT
TB.UID as '#tariffid',
TB.Tariff_Name as '#name',
TB.Carrier as '#network',
TB.Inclusive_Minutes as '#mins',
TB.Inclusive_Texts as '#texts',
TB.Inclusive_Data as '#data',
TB.Monthly_Cost as '#monthly',
TB.Commission as '#comm',
(TB.Commission - PB.Trade_Price) as '#upfront'
FROM dbo.Tariff_Base TB
WHERE TB.Active = 1 AND TB.Type = 1
FOR XML PATH('tariff'), TYPE
),
(SELECT
OP.GP_Margin as '#gpmargin'
FROM dbo.Options OP
FOR XML PATH('options'), TYPE
)
FROM dbo.Phone_Base PB
WHERE PB.Friendly_URL_Name = #phone AND PB.Active = 1
FOR XML PATH('detail'), TYPE
END
What I want to do is:
In the inner select (TB) is to call another SP lets call it "calculate" passing 2 variables (TB.Commission and PB.Trade_Price) for the sum
Calculate will return a value i.e. #hp to the stored procedure which can be added/used in the XML List.
Can this be done in SQL Server 2014/T-SQL?
No. But you could do it with a function. See the MSDN documentation, especially example A.
Something like this (untested):
CREATE FUNCTION dbo.Calculate (#Comission float, #TradePrice float)
RETURNS float
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #SumVal float;
SET #SumVal = #Commission + # TradeValue;
RETURN(#SumVal);
END;
GO
--In your sub-query
SELECT values, dbo.Calculate(TB.Commission, PB.Trade_Price) AS A_Sum
FROM ...;

DESCENDING/ASCENDING Parameter to a stored procedure

I have the following SP
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = #webRegionID)
ORDER BY
CASE UPPER(#sortBy)
when 'CASE_NO' then case_no
when 'AREA' then area
when 'FURNISHED' then furnished
when 'TYPE' then [type]
when 'SQUAREFEETS' then squarefeets
when 'BEDROOMS' then bedrooms
when 'LIVINGROOMS' then livingrooms
when 'BATHROOMS' then bathrooms
when 'LEASE_FROM' then lease_from
when 'RENT' then rent
else case_no
END
END
GO
Now everything in that SP works but I want to be able to choose whether I want to sort ASCENDING or DESCENDING.
I really can't fint no solution for that using SQL and can't find anything in google.
As you can see I have the parameter sortDirection and I have tried using it in multiple ways but always with errors... Tried Case Statements, IF statements and so on but it is complicated by the fact that I want to insert a keyword.
Help will be very much appriciated, I have tried must of the things that comes into mind but haven't been able to get it right.
You could use two order by fields:
CASE #sortDir WHEN 'ASC' THEN
CASE UPPER(#sortBy)
...
END
END ASC,
CASE #sortDir WHEN 'DESC' THEN
CASE UPPER(#sortBy)
...
END
END DESC
A CASE will evaluate as NULL if none of the WHEN clauses match, so that causes one of the two fields to evaluate to NULL for every row (not affecting the sort order) and the other has the appropriate direction.
One drawback, though, is that you'd need to duplicate your #sortBy CASE statement. You could achieve the same thing using dynamic SQL with sp_executesql and writing a 'ASC' or 'DESC' literal depending on the parameter.
That code is going to get very unmanageable very quickly as you'll need to double nest your CASE WHEN's... one set for the Column to order by, and nested set for whethers it's ASC or DESC
Might be better to consider using Dynamic SQL here...
DECLARE #sql nvarchar(max)
SET #sql = '
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = ' + #webRegionID + ') ORDER BY '
SET #sql = #sql + ' ' + #sortBy + ' ' + #sortDirection
EXEC (#sql)
You could do it with some dynamic SQL and calling it with an EXEC. Beware SQL injection though if the user has any control over the parameters.
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
DECLARE #dynamicSQL NVARCHAR(MAX)
SET #dynamicSQL =
'
SELECT
tbl_houses.*
FROM
tbl_houses
WHERE
postal
IN
(
SELECT
zipcode
FROM
crm_zipcodes
WHERE
web_region_id = ' + CONVERT(nvarchar(10), #webRegionID) + '
)
ORDER BY
' + #sortBy + ' ' + #sortDirection
EXEC(#dynamicSQL)
END
GO

TSQL -- Inserting Dates Into Dynamic SQL

Consider the following TSQL:
SET #WhereClause1 = 'where a.Date > ' + #InvoiceDate
I get a date/string conversion error. #InvoiceDate is a datetime variable. What is the right syntax?
This might work.
SET #WhereClause1 = 'where a.Date > ''' + convert(varchar, #InvoiceDate) + ''''
although an error will be raised if the value is null.
This will work:
SET #WhereClause1 = 'where a.Date > ''' + cast(#InvoiceDate as varchar(100)) + ''''
Since your composing query as a string first, then I think you need to convert #InvoiceDate to a string with something like this. http://www.databasejournal.com/features/mssql/article.php/10894_2197931_1/Working-with-SQL-Server-DateTime-Variables-Part-Two---Displaying-Dates-and-Times-in-Different-Formats.htm
... and you will probably need to enclose date strings in quotes.
It would probably actually be better to construct the date string in the calling routine because you should be checking there for null values and maybe other validations.
EXEC sp_executesql N'SELECT * FROM Orders WHERE a.Date > #date',
N'#date datetime',
#date = #InvoiceDate