SQL Server stored procedure SELECT statement with few IF statement - sql-server

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)

Related

SQL Server : input a string of IDs and Return a string of values

I have a table called tblEventDates with DateID and EventDate columns. I need to provide a stored procedure the param of #DateIDs which is a string of DateIDs separated by a pipe, and return a string of EventDates separated by a comma.
This is what I have tried so far
CREATE PROCEDURE [dbo].[ParseDates]
#DateIDs VARCHAR(100),
#ReturnDates VARCHAR(8000) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #i INT,
#DateID INT,
#D VARCHAR(8000),
#TmpDate VARCHAR(8000)
SET #D = #DateIDs
SET #i = CHARINDEX('|', #D)
WHILE #i > 0
BEGIN
SET #DateID = CONVERT(INT, SUBSTRING(#D, 1, #i - 1))
SELECT #TmpDate = EventDate
FROM tblEventDates
WHERE DateID = #DateID
SET #ReturnDates = CONCAT(#ReturnDates, ', ', #TmpDate)
SET #D = SUBSTRING(#D, #i + 1, 9999)
SET #i = CHARINDEX('|', #D)
CONTINUE
END
IF LEN(#D) > 0
BEGIN
SELECT #TmpDate = EventDate
FROM tblEventDates
WHERE DateID = #DateID
SET #ReturnDates = CONCAT(#ReturnDates, ', ', #TmpDate)
END
END
GO
So if #DateIDs = '65|67|69', #ReturnDates should be '01/15/2019, 01/16/2019, 01/17/2019'.
There's a brute force option as well
Example
Declare #S varchar(max) = '65|67|69'
Set #S='|'+#S+'|'
Select #S = replace(#S,concat('|',DateID,'|'),'|'+convert(varchar(10),EventDate,101)+'|')
From tblEventDates
Select replace(substring(#S,2,len(#S)-2),'|',', ')
Returns
01/15/2019, 01/16/2019, 01/17/2019
Providing you are using SQL Server 2016 or higher, you can leverage the STRING_SPLIT function to turn the delimited #DateIDs string into a table, join that against your date table (which I have called my_date_table with the fields id and date_value), and then concatenate the dates using a trick involving JSON_VALUE and REPLACE (found here):
DROP TABLE IF EXISTS #dates;
SELECT
CONVERT(VARCHAR(10), my_date_table.date_field, 101) AS date_string
INTO #dates
FROM my_date_table
INNER JOIN (
SELECT [value]
FROM STRING_SPLIT(#DateIDs, '|')
) date_ids
ON date_ids.[value] = my_date_table.id
;
SET #returnDates = COALESCE(
JSON_VALUE(
REPLACE(
(
SELECT
_ = date_string
FROM #dates
FOR JSON PATH
)
,'"},{"_":"',', '),'$[0]._'
)
, '');

Inserting Function into SQL Statement

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;

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 Row Into Column

We have a table showing amounts (CHGCNT) for 3 dates (5-9-2016, 5-10-2016, 5-11-2016) for each store & Depts.
I want to be able to see the records in a table like this:
I already applied the following query
declare #dt as datetime
declare #dt1 as varchar(10)
declare #dt2 as varchar(10)
declare #dt3 as varchar(10)
select distinct #dt = min(effdt) from [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
-- print CONVERT(CHAR(10), #dt, 110) + ' ---- ' + CONVERT(CHAR(10), #dt+1 , 110)
set #dt1 = CONVERT(CHAR(10), #dt, 110)
set #dt2 = CONVERT(CHAR(10), #dt +1 , 110)
set #dt3 = CONVERT(CHAR(10), #dt + 2 , 110)
--print #dt1 + ' ---- ' + #dt2 + '-----' + #dt3
SELECT DEPTNM, DEPT, [#dt1] , [#dt2] , [#dt3]
FROM [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
PIVOT
(
SUM(CHGCNT)
FOR effdt IN ( [#dt1] , [#dt2] , [#dt3])
) AS P
but it is returning dates
I like the SUM-CASE approach:
SELECT deptnm,
SUM(CASE WHEN effdt = '2016-05-09' THEN chgcnt ELSE 0 END) "2016-05-09",
SUM(CASE WHEN effdt = '2016-05-10' THEN chgcnt ELSE 0 END) "2016-05-10",
SUM(CASE WHEN effdt = '2016-05-11' THEN chgcnt ELSE 0 END) "2016-05-11",
SUM(effdt) Total
FROM [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
GROUP BY deptnm;

How to return a string in reverse separated by a special character in SQL?

I have a string like this "Planck, Albert, Bohr"
I want the output as "Bohr Albert Planck"
I want this done using SQL server. I saw many string split functions all return the data as a table and in the forward order. These don't server my purpose.
Any pointers will be helpful.
This what you want:
DECLARE #source VARCHAR(MAX)
DECLARE #dest VARCHAR(MAX)
DECLARE #lenght INT
SET #source = 'Planck, Albert, Bohr'
SET #dest = ''
WHILE LEN(#source) > 0
BEGIN
IF CHARINDEX(' ', #source) > 0
BEGIN
SET #dest = SUBSTRING(#source,0,CHARINDEX(' ', #source)) + ' ' + #dest
SET #source = LTRIM(RTRIM(SUBSTRING(#source,CHARINDEX(' ',
#source)+1,LEN(#source))))
END
ELSE
BEGIN
SET #dest = #source + ' ' + #dest
SET #source = ''
END
END
SELECT REPLACE(REPLACE(#dest,Char(44),''),Char(13), '')
Char(44) is the ASCII value for , so at last I am just replacing that character.
This will print Bohr Albert Planck.
If you use a split string function like this you can do something like this.
declare #S varchar(20) = 'Planck, Albert, Bohr'
select
(
select ltrim(s)+' '
from dbo.Split(',', #S)
order by pn desc
for xml path(''), type
).value('.', 'varchar(max)')
SQL Fiddle
Declare #inStr varchar(1000)='Planck, Albert, Bohr'
;WITH CTE AS(
select ltrim(rtrim(reverse(left(reverse(#instr),CHARINDEX(',',reverse(#instr),1)-1)))) as strg,RIGHT(reverse(#instr),LEN(reverse(#instr))-CHARINDEX(',',reverse(#instr),1)) as rem
union all
select CASE WHEN CHARINDEX(',',c.rem,1)>0 then ltrim(rtrim(reverse(left(rem,CHARINDEX(',',rem,1)-1)))) else reverse(rem) end,
CASE WHEN CHARINDEX(',',c.rem,1)>0 then RIGHT(c.rem,LEN(rem)-CHARINDEX(',',rem,1)) else '' end
from CTE c
where len(rem) > 0 --CHARINDEX(',',c.rem,1)>0
)
select stuff((select ' '+strg from CTE for xml path('')),1,1,'')

Resources