I tried to create a function with a conditional calculation before the RETURN statement, but SSMS states that there is an incorrect syntax near 'BEGIN IF #param2 IS NULL' and I can't figure out what is wrong with this code:
CREATE FUNCTION ConditionalFunction
(
#input1 VARCHAR(20),
#input2 VARCHAR(20)
)
RETURNS TABLE
AS BEGIN
IF #input2 IS NULL
BEGIN
SET #input2 = field
FROM table1
WHERE filter = #input1
END
RETURN
(
SELECT field1, field2
FROM table2
WHERE filter1 = #input1
AND filter2 = #input2
)
END
My goal is to be able to call it either
ConditionalFunction('Foo',NULL)
or
ConditionalFunction('Foo','Bar')
In a way that the first call will make it detect a default value for #input2 based on #input1.
I wrote this code based on this answer.
This is SQL Server 13. Could you please tell me if there is anything I can do to make it compile?
N.B: I obviously replaced real names with generics, but the code structure remains the same
Try this, but change the #Data table types to your data types:
CREATE FUNCTION ConditionalFunction
(
#input1 VARCHAR(20),
#input2 VARCHAR(20)
)
RETURNS #Data TABLE
(
field1 VARCHAR(12)
,field2 VARCHAR(12)
)
AS
BEGIN
IF #input2 IS NULL
BEGIN
SET #input2 = field
FROM table1
WHERE filter = #input1
END
INSERT INTO #Data
SELECT field1, field2
FROM table2
WHERE filter1 = #input1
AND filter2 = #input2
RETURN;
END
There are several types of functions in SQL:
scalar return only one value
inline - returns a table (it is like view with parameters)
table-valued - returns a table
Your syntax looks like you need a inline function, but should contain only one SELECT statement returning the data. So, you need to create a table-valued function.
Related
I need to write a SQL function to return column specific values, so I am passing the column name as a parameter to SQL-function to return its corresponding value. Here is the sample function
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
RETURN (SELECT TOP 1.#columnName FROM TEST_TABLE )
END
GO
The above function seems to be straight forward, but it not working as expected.
And when I execute the function
SELECT dbo.GETDATETIME('DATETIMECOLUMNNAME')
I am getting this error:
Conversion failed when converting date and/or time from character string.
Can someone help me to identify the issue?
For that you need to write dynamic sql. But Functions won't support execute statement.
So you need to write multiple If conditions for each column.
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
IF (#columnName = 'ABC')
Begin
SELECT TOP 1 #RESULT = [ABC] FROM TEST_TABLE
END
ELSE IF (#columnName = 'DEF')
Begin
SELECT TOP 1 #RESULT = [DEF] FROM TEST_TABLE
END
ELSE IF (#columnName = 'GHI')
Begin
SELECT TOP 1 #RESULT = [GHI] FROM TEST_TABLE
END
RETURN #RESULT
END
GO
Edit 2:
If your column always return Datetime, then you can do like below.
CREATE TABLE A_DUM (ID INT, STARTDATE DATETIME, ENDDATE DATETIME, MIDDLEDATE DATETIME)
INSERT INTO A_DUM
SELECT 1, '2019-07-24 11:35:58.910', '2019-07-28 11:35:58.910', '2019-07-26 11:35:58.910'
UNION ALL
SELECT 2, '2019-07-29 11:35:58.910', '2019-08-01 11:35:58.910', '2019-07-24 11:35:58.910'
And your function like below
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
SELECT TOP 1 #RESULT = CAST(PROP AS DATETIME)
FROM A_DUM
UNPIVOT
(
PROP FOR VAL IN (STARTDATE, ENDDATE,MIDDLEDATE)
)UP
WHERE VAL = #columnName
RETURN #RESULT
END
GO
There's a workaround to this, similar to #Shakeer's answer - if you are attempting to GROUP BY or perform a WHERE on a column name, then you can just use a CASE statement to create a clause to match on specific column names (if you know them).
Obviously this doesn't work very well if you have many columns to hard-code, but at least it's a way to achieve the general idea.
E.g. with WHERE clause:
WHERE
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnCondition
WHEN #columnname = 'SecondColumn' THEN SecondColumnCondition
ELSE SomeOtherColumnCondition
END)
Or with GROUP BY:
GROUP BY
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnGroup
WHEN #columnname = 'SecondColumn' THEN SecondColumnGroup
ELSE SomeOtherColumnGroup
END)
No you cannot use dynamic sql in functions in SQL. Please check this link for more info link.
So it is not possible to achieve this by any function, yes you may use stored procedures with output parameter for same.
You may find this link for reference link.
How to achieve below requirement in SQL Server.
Data what I have:
and Expected output is:
Thanks,
Lawrance A
Assuming of your given data value:
'Message:"A",Level:"0",type:"log"'
'Message:"B",Level:"1",type:"log"'
select substring(ColumnA,10,1) Message,
replace(dbo.udf_GetNumeric(replace(replace(substring(ColumnA,20,5),'"',''),',','')),' ','')[type],
replace(replace(substring(ColumnA,29,250),'"',''),',','')[Log] from YourTable
GetNumeric here
I have created two function to achieve your desired output.
use below query by creating two function split and getVal
select
dbo.getVal(columnA,'Message') Message,
dbo.getVal(columnA,'Level') [Level],
dbo.getVal(columnA,'type') [type]
from TableA
Query for creating split and getVal function
Create function split(#s varchar(500),#splitWith varchar(20))
returns #RetTable Table(id int identity(1,1), Value varchar(200))
as
begin
if(CHARINDEX(#splitWith,#s)>0)
begin
set #s=#s+#splitWith
declare #len int =len(#s)
while charindex(#splitWith,#s)>0
begin
insert #RetTable values(SUBSTRING(#s,1,charindex(#splitWith,#s)-1))
set #s=SUBSTRING(#s,charindex(#splitWith,#s,1)+1,#len)
end
end
return
end
Create function getVal(#str varchar(500),#column varchar(200))
returns varchar(200)
as
begin
declare #ret varchar(200)
select #ret=value From dbo.split((select value From dbo.split('Message:"A",Level:"0",type:"log"',',') where value like +#column+'%'),':') where id=2
return replace(#ret,'"','')
end
I've created the following stored procedure:
ALTER PROCEDURE [dbo].[CountInJunction]
#Mod as nvarchar(10),
#Junction as nvarchar(10),
#PJ as nvarchar(10),
**#case as varchar(10)**,
#Date as varchar(20)
as
begin
declare #result as int
select #result = count(distinct CONCAT ([UCID],[CALLSEGMENT]))
from IVR_LINES
where MODULE = #Mod and DATE = #date
and EVENT_NAME = #Junction and **EVENT_VALUE in (#case)**
insert into [dbo].[MainJuncTable] values(#Mod,#PJ,#Junction,#case,#result,null,null,#date)
return #result
end
I would like to pass ('0','5') as #case.
for some reason, I get 0 as a result, which is not correct. Its seems that the SP doesn't interpret ('0','5') correctly.
I've been trying multiple combinations such as:
'0','5'
'0'+','+5''
'0,5'
etc..
nothing works.
Is there any way I can pass these chars correctly?
Thanks.
Send the values as a single string like ('0,5')
Then in where condition u need to split and select the values like,
where EVENT_VALUE in (select val from Split(#case,','))
Split is user defined function,you need to create before using it.
CREATE FUNCTION [dbo].[Split]
(
#delimited nvarchar(max),
#delimiter nvarchar(100)
) RETURNS #t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id int identity(1,1), -- I use this column for numbering splitted parts
val nvarchar(max)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#delimited,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(max)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
GO
In every case, use this as your parameter value: '0,5'
But how to use it depends on the version of sql server you're using.
If you've got 2016, there's STRING_SPLIT. https://msdn.microsoft.com/en-us/library/mt684588.aspx
If you don't have it, you can create a function. See related stackoverflow posts: How to split a comma-separated value to columns
Or if you want rows: SQL query to split column data into rows
(See the higher rated recommendations in both of those.)
I have a stored procedure that take many input parameters including an #userID.
Now, in the core of the SP I select from a view using the following Where close :
Where userID = #userID
This works fine. Now I want to pass multiple users to be able wo query it like this :
where userID in (1,2,...)
How can I pass the value 1,2 from one input parameter ?
Thanks
Create a function split:
create FUNCTION [dbo].[Split]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(2000)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
--select Value from dbo.Split('item1, item2, item3',',')
END
GO
And call the function with #PASS and use it inside a cursor.
Arrays and Lists in SQL Server
Create an input parameter which is a table varaible and send in the array as a table that you join to instead of using in. Read about this in BOL as it can be a little tricky to set up.
Strange situation
In a trigger i assign a column value to variable but gives exception while inserting into other table using that variable.
e.g
select #srNO=A.SrNo from A where id=123;
insert into B (SRNO) values (#srNo) // here it gives null
I run above select query in query pane it works fine but in trigger it gives me null
any suggestions
ALTER PROCEDURE ProcessData
#Id decimal(38,0),
#XMLString varchar(1000),
#Phone varchar(20)
AS
DECLARE
#idoc int,
#iError int,
#Serial varchar(15),
#PhoneNumber varchar(15),
BEGIN
COMMIT TRAN
EXEC sp_xml_preparedocument #idoc OUTPUT,#XMLString<br/>
SELECT #iError = ##Error<br/>
IF #iError = 0<br/>
BEGIN<br/>
SELECT #Serial = convert(text,[text]) FROM OPENXML (#idoc,'',1) where nodetype = 3 and ParentId = 2
IF #Serial=Valid <br/>
BEGIN<br/>
BEGIN TRAN INVALID<br/>
begin try <br/>
Declare #phoneId decimal(38,0);<br/>
SELECT #phoneId = B.phoneId FROM A
INNER JOIN B ON A.Id = B.Id WHERE A.PhoneNumber like '%'+#SenderPhone + '%'<br/>
print #phoneId ; //gives null<br/>
end try<br/>
begin catch<br/>
print Error_Message();<br/>
end catch<br/>
you should work with sets of rows in triggers, so if multiple rows are affected your code handles all rows. This will only INSERT when the value is not null:
INSERT INTO B (SRNO)
SELECT A.SrNo FROM A where id=123 AND A.SrNo IS NOT NULL
Neo, are you sure, that SELECT SrNo FROM A WHERE id = 123 returns data?
I mean, value of #srNo will not change (therefore, remain NULL) if there no records with id = 123
When you eliminate the impossible, whatever remains, however improbable, must be the truth.
The obvious answer is that at the time the trigger fires, SrNo is null or Id 123 does not exist. Is this for an insert trigger and is it the case that you are trying to take something that was just inserted into table A and push it into table B? If so, you should query against the inserted table:
//from an insert trigger on the table `A`
Insert B( SRNO )
Select SRNO
From inserted
Where Id = 123
If this is not the case, then we'd need to see the details of the Trigger itself.
solved it there is some error in xml string reading function
e.g in openxml pattern matching
Thanks all of you for help... :)