Inserting Function into SQL Statement - sql-server

Brand new to functions. Received function from someone else to solve for html tags in a data pull. No idea how to incorporate this code into my query.
CREATE FUNCTION [dbo].[mcl_RemoveVisionMemoFormat]
(#String NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
declare #start int,
#end int,
#length int
while charindex('<', #string) > 0 and charindex('>', #string, charindex('<',
#string)) > 0
begin
select #start = charindex('<', #string),
#end = charindex('>', #string, charindex('<', #string))
select #length = (#end - #start) + 1
if #length > 0
begin
select #string = stuff(#string, #start, #length, '')
end
end
return replace(#string , ' ' , ' ')
END
Above function needs to be added to a basic SELECT statement
SELECT LD.WBS1 as [Project Number], LD.Name, LD.Comment, LD.TransDate as
[Comment Date]
FROM LD
WHERE (((LD.Comment) Is Not Null))
ORDER BY LD.TransDate DESC;
Much appreciated!

Your question is strictly how to use a scalar function in a query using a column as a parameter
To do this, you just add the function to the select statement and pass in the column.
Select [schema].[ScalarFunction](column) as [ColumnName] from [schema].table
For the query you provided, you just add the function [dbo].[mcl_RemoveVisionMemoFormat] followed by the column name LD.Comment in parenthesis
SELECT LD.WBS1 as [Project Number], LD.Name, LD.Comment, LD.TransDate as [Comment Date], [dbo].[mcl_RemoveVisionMemoFormat](LD.Comment) as [CommentWithoutVisionMemoFormat]
FROM LD
WHERE LD.Comment IS NOT NULL
ORDER BY LD.TransDate DESC;

Related

SQL Server stored procedures dynamic SQL with multiple different where clause

Input CASE1=wen #type is NULL-> WHERE c.Date_Redeemed BETWEEN #Start AND #End-- this should execute
If CASE2=wen #start,#end is NULL->WHERE c.Type=#type-- this should execute
CASE 3=wen #value is null->WHERE c.Date_Redeemed BETWEEN #Start AND #End AND c.Type=#type this should execute
CASE4=wen #marketclass is NULL->WHERE c.Date_Redeemed BETWEEN #Start AND #End AND c.Type=#type AND c.ordervalue BETWEEN #price1 AND #price2
VAR=#type,#start,#price1,#marketclass if eithr of var is NULL dynamicaly other input where condition has to execute like diff combination of input comes
WHERE
(c.Type = #type AND o.Date_of_Purchase BETWEEN #start AND #end) OR
(#start IS NULL AND c.Type = #type) OR
(#type IS NULL and o.Date_of_Purchase BETWEEN #start AND #end) OR
(#start IS NULL AND #type IS NULL)
if both are provided, only rows where type and date match are returned,
if type is not provided, date is used,
if date not provided type is used and
if nothing provided all rows return. To make no rows return, remove the last predicate
Code:
CREATE PROCEDURE dbo.sample
#start DATE, #end DATE,
#type VARCHAR(5),
#price1 MONEY, #price2 MONEY
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL VARCHAR(MAX)
SET #SQL= 'SELECT DISTINCT o.O_Id,o.Sale_Price,o.Order_Line_Id,Private_Band,c.Date_of_Purchase,c.Date_Redeemed,c.Credit_Memo,c.Credit_Memo_Created_Date,c.Credit_Memo_Approved_Date,
c.Type,c.Points_Issued,o.Date_of_Purchase FROM Order_Details o ,Transaction_Historys c WHERE -1='-1''
IF #type IS NOT NULL AND #type <> 0
SET #SQL = #SQL+ 'c.Type = #type'
ELSE
IF #start IS NOT NULL AND #start <> 0
SET #SQL = #SQL+ 'c.Date_redeemed BETWEEN #start AND #end'
EXECUTE dbo.sample #type='Earn',#start='2010-02-10',#end='2020-04-11'
END
Having looked through this, I'm actually kind of reluctant to post this answer, because there's so many things wrong with this:
prone to SQL injection;
using antiquated JOIN syntax;
clunky logic.
The simple answer is that sometimes just because you CAN do something in SQL doesn't mean you actually SHOULD.
Anyway, I think is closer to what you wanted?
CREATE PROCEDURE dbo.[sample] (
#start DATE,
#end DATE,
#type VARCHAR(5),
#price1 NUMERIC(9,2),
#price2 NUMERIC(9,2))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql VARCHAR(1024);
SELECT #sql = N'
SELECT DISTINCT
o.O_Id,
o.Sale_Price,
o.Order_Line_Id,
Private_Band, --alias?
c.Date_of_Purchase,
c.Date_Redeemed,
c.Credit_Memo,
c.Credit_Memo_Created_Date,
c.Credit_Memo_Approved_Date,
c.Type,
c.Points_Issued,
o.Date_of_Purchase
FROM
Order_Details o,
Transaction_Historys c'; --Join condition?!
DECLARE #constraint VARCHAR(1024) = '';
IF #type IS NOT NULL AND #type != 0
BEGIN
SELECT #constraint = CONCAT(' WHERE c.Type = ''', #type, '''');
END;
IF #start IS NOT NULL AND #end IS NOT NULL
BEGIN
SELECT #constraint = CONCAT(#constraint,
CASE WHEN #constraint = '' THEN ' WHERE ' ELSE ' AND ' END,
' c.Date_redeemed BETWEEN ''',
CONVERT(VARCHAR(12), #start, 112),
''' AND ''',
CONVERT(VARCHAR(12), #end, 112)),
'''';
END;
SELECT #sql = CONCAT(#sql, #constraint);
EXEC sp_executesql #sql;
END;
GO
EXEC dbo.[sample] #type = 'Earn', #start = '20100210', #end = '20200411', #price1 = NULL, #price2 = NULL;
I made quite a few changes here:
I couldn't bring myself to use a MONEY type, so change it back if you really want it;
I added some comments to your script ;)
I sort of fixed the actual issue, that you need to cope with one or two or even no constraints being passed in.

INSERT using T-SQL with 2 table-value functions

I have a stored procedure that accepts two NVARCHAR parameters that accept a comma delimited list of name & index values and to insert them into a SQL Server database table in one go.
CREATE PROCEDURE [dbo].[SplitAndSave]
#name nvarchar(MAX),
#vals nvarchar(MAX)
The data would be in the format with each of the #name ids matching in the same sequence as the #vals:
#name = 1,2,3,4
#vals = 9,8,7,6
I have found a function that splits one column into a table which works fine independently and splits the data into the rows that is required:
CREATE FUNCTION [dbo].[fnSplitString] (
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE #start INT, #end INT
SELECT #start = 1, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1 BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
INSERT INTO #output (splitdata)
VALUES(SUBSTRING(#string, #start, #end - #start))
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
RETURN
END
In my stored procedure I am trying to 'combine' the two table functions:
INSERT INTO KEY_DATA (name, value)
(SELECT splitdata from fnSplitString(#name, ',')), (SELECT splitdata from fnSplitString(#value, ','))
But I get an error:
Msg 512, Level 16, State 1, Procedure dbo.SplitAndSave, Line 17 [Batch Start Line 2]
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I think I might need to wrap the first table into the second, but I don't think this can be done 'all in one go'.
Any thoughts how I can achieve this? Currently using SQL Server Management Studio v17.8
The issue is not the function but how you are inserting the data. The following code:
INSERT INTO KEY_DATA (name, value)
(SELECT splitdata from fnSplitString(#name, ',')), (SELECT splitdata from fnSplitString(#value, ','))
except:
INSERT INTO KEY_DATA (name, value)
(one value of name), (one value of value)
but in your statements are returning more then one value. That's the issue.
You need to add order index in your function and join the function by it. Something like this:
INSERT INTO KEY_DATA (name, value)
SELECT DS1.splitdata
,DS2.splitdata
from fnSplitString(#name, ',') DS1
INNER JOIN fnSplitString(#value, ',') DS2
ON DS1.[OrderIndex] = DS2.[OrderINdex];
For example:
CREATE OR ALTER FUNCTION [dbo].[fnSplitString]
(
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE
(
[orderID] BIGINT
,[splitdata] NVARCHAR(MAX)
)
BEGIN
DECLARE #XML XML = CAST(N'<r><![CDATA[' + REPLACE(#string, #delimiter, ']]></r><r><![CDATA[') + ']]></r>' AS XML)
INSERT INTO #output ([orderID], splitdata)
SELECT ROW_NUMBER() OVER(ORDER BY T.c)
,RTRIM(LTRIM(T.c.value('.', 'nvarchar(MAX)')))
FROM #XML.nodes('//r') T(c)
RETURN
END
GO
DECLARE #name NVARCHAR(MAX) = '1,2,3,4'
,#vals NVARCHAR(MAX) = '9,8,7,6'
SELECT DS1.[splitdata]
,DS2.[splitdata]
from dbo.fnSplitString(#name, ',') DS1
INNER JOIN dbo.fnSplitString(#vals, ',') DS2
ON DS1.[orderID] = DS2.[orderID];

Split in sql server

enter image description hereI have table having Column "Title" having multiple String value with comma I want to split it with comma & move to next line in same column is that possible with SQL SERVER.i want it in same row but next line.
Eg: Test1,Test2,Test3,Test4
Expected:
Test1
Test2
Test3
...
As you described it, you want the result to be in one field. So you do not want to split the value, but replace the , with a line break.
Select replace(title,',',char(13)+char(10))
SSMS does not show line breaks, but they are present in the result.
This code may helps you
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
CReate table #t (Title nvarchar(1000))
INSERT INTO #t
SELECT 'Test1,Test2,Test3,Test4'
SELECT
SPlit.a.value('.','nvarchar(1000)') AS Title FROM
(
SELECT
CAST('<S>'+REPLACE(Title,',','</S><S>')+'</S>' AS XML ) AS Title FROM #t
)A
CROSS APPLY Title.nodes('S') AS SPlit(a)
Result
Title
-----
Test1
Test2
Test3
Test4
Yes it is possible. You can create a function first to achieve it. Here is the function you can use :
CREATE FUNCTION [dbo].[fnSplitString]
(
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE #start INT, #end INT, #temp varchar(max)
set #temp = ''
SELECT #start = 1, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1 BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
SET #temp = #temp + CHAR(13)+CHAR(10) + SUBSTRING(#string, #start, #end - #start)
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
INSERT INTO #output (splitdata)
VALUES(#temp)
RETURN
END
And then you can make the query like below :
select *from dbo.fnSplitString('Test1,Test2,Test3,Test4',',')

SQL Server T-SQL: automate re-occuring SQL reports with stored procedure

GOAL: create a stored procedure that automates this report, so that when execute NameOfStoredProc is run, it does all 3 blocks and returns the query in block 3.
For into table, I want it to be dynamic based on getdate().
(I did not post actual table elements and records, but if needed I can make up something b/c actual data is sensitive)
Database: FY1516
From table: v_all_claim (actually a view)
Into table: March2017_Payments
Here's the code that I execute manually to generate the report.
Block 1:
--creates payment table
SELECT Recipient_ID, DOP, Provider_ID, program_code, poverty_code
INTO FY1516..March2017_Payments
FROM FY1516..v_all_Claim
WHERE amount <> 0
AND DOP BETWEEN '20170301' AND '20170331'
Block 2:
-- add one column to the table created in block 1, sets default value to '' and update to Y
-- if certain constraints are met
ALTER TABLE FY1516..March2017_Payments
ADD TITLE21_Flag varchar(1);
GO
UPDATE FY1516..March2017_Payments
SET TITLE21_Flag = ''
GO
UPDATE FY1516..March2017_Payments
SET TITLE21_Flag = 'Y'
WHERE program_code IN ('A', 'B', 'C')
Block 3 with select statement that gets copied into Excel:
SELECT *
FROM FY1516..March2017_Payments
My attempts thus far:
#start and #end are for between #start and #end
#previousMonth gives first 3 letters of previous month
#previousMonthYear gives the YYYY of the previous month
Hoping #previousMonth +#previousMonthYear +"_Payments" can be the tablename
USE FY1516
CREATE PROCEDURE NameOfStoredProc
AS
DECLARE #start VARCHAR(8), #end VARCHAR(8),
#previousMonth VARCHAR(3), #previousMonthYear VARCHAR(4);
SET #start = CONVERT(VARCHAR(8), DATEADD(MONTH, DATEDIFF(MONHT, 0, GETDATE()) - 1, 0), 112)
SET #end = CONVERT(VARCHAR(8), DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()) - 1, -1), 112)
SET #previousMonth = LEFT(DATENAME(MONTH, DATEADD(MONTH, -1, GETDATE())), 3)
SET #previousMonthYear = YEAR(DATEADD(MONTH, -1, GETDATE()))
You can combine Block 1 and Block 2 into a single statement:
--creates payment table
Select Recipient_ID
, DOP
, Provider_ID
,program_code
,poverty_code
,TITLE21_Flag = CASE WHEN program_code IN ('A','B','C') THEN 'Y' ELSE '' END
INTO FY1516..March2017_Payments
FROM FY1516..v_all_Claim
WHERE amount <> 0 and DOP between '20170301' and '20170331'
Then, in your proc, you can use dynamic SQL to create your tables. Here's an example:
Create procedure NameOfStoredProc
AS
declare #start varchar(8)
, #end varchar(8)
,#previousMonth varchar(3)
,#previousMonthYear varchar(4);
set #start = convert(varchar(8),dateadd(month, datediff(month,0,getdate())-1,0),112)
set #end = convert(varchar(8),DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1),112)
set #previousMonth = left(datename(month, dateadd(month,-1,getdate())), 3)
set #previousMonthYear = year(dateadd(month,-1,getdate()))
DECLARE #SQLString NVARCHAR(MAX) = 'CREATE TABLE ' + #previousMonth +#previousMonthYear +'_Payments (ColA int)'
EXECUTE sp_executesql #SQLString
You'll want to replace the (ColA int) with your actual column names and data types.
EDIT:
Here's an example that includes Block 1/2 into the stored proc. It checks the existence of the table first, and then runs the appropriate SELECT query.
CREATE PROCEDURE NameOfStoredProc
AS
begin
declare #start varchar(8)
, #end varchar(8)
,#previousMonth varchar(3)
,#previousMonthYear varchar(4);
set #start = convert(varchar(8),dateadd(month, datediff(month,0,getdate())-1,0),112)
set #end = convert(varchar(8),DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1),112)
set #previousMonth = left(datename(month, dateadd(month,-1,getdate())), 3)
set #previousMonthYear = year(dateadd(month,-1,getdate()))
DECLARE #SQLString NVARCHAR(MAX) =
'IF OBJECT_ID('''+#previousMonth +#previousMonthYear +'_Payments'', ''U'') IS NOT NULL
BEGIN
print 1
INSERT INTO FY1516..'+ #previousMonth +#previousMonthYear +'_Payments
Select Recipient_ID
, DOP
, Provider_ID
,program_code
,poverty_code
,TITLE21_Flag = CASE WHEN program_code IN (''A'',''B'',''C'') THEN ''Y'' ELSE '''' END
FROM FY1516..v_all_Claim
WHERE amount <> 0 and DOP between ''20170301'' and ''20170331''
END
ELSE
BEGIN
print 2
Select Recipient_ID
, DOP
, Provider_ID
,program_code
,poverty_code
,TITLE21_Flag = CASE WHEN program_code IN (''A'',''B'',''C'') THEN ''Y'' ELSE '''' END
INTO FY1516..'+ #previousMonth +#previousMonthYear +'_Payments
FROM FY1516..v_all_Claim
WHERE amount <> 0 and DOP between ''20170301'' and ''20170331''
END
'
EXECUTE sp_executesql #SQLString
SET #SQLString = 'SELECT * FROM '+#previousMonth +#previousMonthYear +'_Payments'
EXECUTE sp_executesql #SQLString
END

SQL Server stored procedure SELECT statement with few IF statement

i have constructed my sql statemnet like the below way but i am getting error when try to compile. i know we can build it dynamically in string but like to know can we write statement like this way. please looking for suggestion.
INSERT INTO #tmpHierarchy (
JID ,
EntryDate ,
RefundDate ,
ActionBy ,
Comments ,
CID,
nLevel
)
SELECT
JID, EntryDate, RefundDate, ActionBy, Comments, CID, nLevel
FROM
Hierarchy
WHERE 1=1
AND
IF #FromDate <> '' AND #ToDate <> ''
BEGIN
Convert(varchar,EntryDate,112)>= #FromDate AND Convert(varchar,EntryDate,112) <= #ToDate
END
IF #ActionBy <> ''
BEGIN
ActionBy=#ActionBy
END
IF #JID > 0
BEGIN
JID=#JID
END
You actually have to build up a varchar with the query and then execute it:
declare #sql varchar(max)
set #sql = 'INSERT INTO #tmpHierarchy (
JID ,
EntryDate ,
RefundDate ,
ActionBy ,
Comments ,
CID,
nLevel
)
SELECT JID,EntryDate,RefundDate,ActionBy,Comments,CID,nLevel FROM Hierarchy WHERE 1=1'
IF #FromDate <> '' AND #ToDate <> ''
BEGIN
#sql = #sql + ' and Convert(varchar,EntryDate,112)>= #FromDate AND Convert(varchar,EntryDate,112) <= #ToDate'
END
IF #ActionBy <> ''
BEGIN
#sql = #sql + ' and ActionBy=#ActionBy'
END
IF #JID > 0
BEGIN
#sql = #sql + ' and JID=#JID'
END
exec (#sql)
You can do something like this where you combine the IF statements into the WHERE clause
SELECT JID, EntryDate, RefundDate, ActionBy, Comments, CID, nLevel
FROM Hierarchy
WHERE 1 = 1
AND (#FromDate = '' OR #ToDate = '' OR (Convert(varchar, EntryDate, 112) >= #FromDate AND Convert(varchar, EntryDate, 112) <= #ToDate))
AND (#ActionBy = '' OR ActionBy = #ActionBy)
AND (#JID <= 0 OR JID = #JID)

Resources