Input variables as stored procedure statement - sql-server

My stored procedure:
ALTER PROCEDURE [dbo].[Perdate]
#D_Data as nvarchar(999)
AS
SELECT 'Total'= SUM(CAST(TBL_Stock.R_TotalPrice as decimal(18,2))),(convert(varchar,TBL_Stock.D_Datepush,105)) as Date
FROM TBL_Stock
GROUP BY (convert(varchar,TBL_Stock.D_Datepush,105))
Having (convert(varchar,TBL_Stock.D_Datepush,105)) = #D_Data
I would like to know if it is possible to set that variable (#D_Data) as something like:
'02-03-2012' or (convert(varchar,TBL_Stock.D_Datepush,105)) = '02-04-2012'
So the having clause would be :
HAVING (convert(varchar, TBL_Stock.D_Datepush, 105)) = '02-03-2012'
OR (convert(varchar, TBL_Stock.D_Datepush, 105)) = '02-04-2012'
So my idea is to have (in my VB.net project) a string that could dynamically change the stored procedure "Future"

Seems like you want to do SQL injection so that your input param "glues into" the TSQL that is being built in your proc. THIS IS A VERY BAD IDEA ( see SQL Injection discussion here).
But good news, dynamic SQL is not needed. Use a table function to parse the incoming string so that it can be joined in the proc.
create table TBL_Stock(R_TotalPrice decimal(18,2), D_Datepush datetime)
insert into TBL_Stock(R_TotalPrice,D_datepush) values(1000,'1/1/2012')
insert into TBL_Stock(R_TotalPrice,D_datepush) values(200,'1/2/2012')
insert into TBL_Stock(R_TotalPrice,D_datepush) values(30,'1/3/2012')
insert into TBL_Stock(R_TotalPrice,D_datepush) values(4,'1/4/2012')
GO
CREATE FUNCTION dbo.SplitDates(#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (dt datetime)
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0 AND isDate(#slice) = 1)
insert into #temptable(dt) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
GO
--test function
select * from dbo.SplitDates('1/1/2012,1/2/2012',',')
GO
create PROCEDURE Perdate #D_Data as nvarchar(2000)
AS
select
PushDate=z.dt,
'Total'= SUM(s.R_TotalPrice)
from
dbo.splitDates(#D_Data,',') z
join TBL_Stock s on s.D_datepush = z.dt
group by
z.dt
GO
--Test proc
select * from TBL_Stock
exec Perdate '1/1/2012'
exec Perdate '1/1/2012,1/2/2012'
exec Perdate '1/1/2012,1/4/12'

Related

Get value from store or store and get if not exists

what I want to achieve is a way to get previously generated or generate, store and return data, in a way, which could be used as function - needed to join or APPLY in UPDATE scripts.
So, having data generate function:
ALTER FUNCTION generateData()
RETURNS NVARCHAR(20)
AS
BEGIN
RETURN 'asdyukyuk' --some rng related algorithm
END
And "get or generate, save and get" procedure:
ALTER PROCEDURE getOrGenerateAndGet (#orig NVARCHAR(20), #result NVARCHAR(20) OUTPUT)
AS
BEGIN
IF #orig IS NULL
BEGIN
SET #result = NULL
END
ELSE
BEGIN
DECLARE #hash VARBINARY(64) = dbo.getHash(#orig)
SELECT #result = GENERATED_DATA FROM STORED_DATA WHERE HASH = #hash
IF #result IS NULL
BEGIN
SET #result = dbo.generateData()
INSERT INTO STORED_DATA (HASH, GENERATED_DATA) VALUES (#hash, #result)
END
END
RETURN 1
END;
GO
And UPDATE script:
UPDATE FRAGILE_DATA SET FRAGILE_COLUMN = getOrGenerateAndGet(FRAGILE_COLUMN)
it's obviously not working, because getOrGenerateAndGet is not function.
However, with function way:
CREATE FUNCTION getOrGenerateAndGet (#orig NVARCHAR(20))
RETURNS NVARCHAR(20)
AS
BEGIN
DECLARE #result NVARCHAR(20)
IF #orig IS NULL
BEGIN
SET #result = NULL
END
ELSE
BEGIN
DECLARE #hash VARBINARY(64) = dbo.getHash(#orig)
SELECT #result = GENERATED_DATA FROM STORED_DATA WHERE HASH = #hash
IF #result IS NULL
BEGIN
SELECT #result = dbo.generateData()
EXEC sp_executesql N'INSERT INTO STORED_DATA (HASH, GENERATED_DATA) VALUES (#hash, #result)'
END
END
RETURN #result
END;
GO
it's still not working, because "Only functions and some extended stored procedures can be executed from within a function."
Is there any way to achieve this, without enabling sql command shell?

SQL SERVER : How to execute an SP specifed number of time without using loop

I have a scenario wherein i have to execute an SP for specified number of time(number of execution will be mentioned by user) without using loop.
My SP is setting an OUTPUT variable of varchar type. I am willing to insert the output of my SP into a temp table and use it for further processing.
I am unable to modify this SP into function as it contain an Update statement.
Kindly suggest if we can do so without loop.
Whit this solution you do not need an output; #res is your result directly set in a temp table.
CREATE PROCEDURE [dbo].[myStoredProc]
#Counter int,
#params nvarchar(64),
#CreateTable bit
AS
DECLARE #res varchar(64)
IF #CreateTable = 1
BEGIN
IF EXISTS (SELECT 1 FROM dbo.sysobjects WHERE id = object_id(N'[#tempTable]'))
DROP TABLE #tempTable
CREATE TABLE #tempTable ([Res] [nvarchar] (64))
END
SET #res = CONVERT(varchar(64), #Counter)
SET #Counter = #Counter - 1
IF #Counter > 0
exec myStoredProc #Counter, #params, 0
INSERT #tempTable VALUES (#res)
IF #CreateTable = 1
BEGIN
SELECT * FROM #tempTable
DROP TABLE #tempTable
END
GO
DECLARE #o varchar(64)
exec [myStoredProc] 5, '', 1

T-SQL How can I use a variable in the WHERE IN clause? [duplicate]

This question already has answers here:
Parameterize an SQL IN clause
(41 answers)
Closed 7 years ago.
I can do this and it works (but would like something more simple):
Declare #PropIDs varchar(50)
Set #PropIDs = '1, 2'
IF OBJECT_ID('dbo.TempProp') IS NOT NULL DROP TABLE dbo.TempProp
CREATE TABLE [dbo].[TempProp](
[PropCode] [VarChar](3) NULL)
Set #Sql = 'Insert Into TempProp Select PropertyCode From Property where PropertyID In (' + #PropIDs + ')'
Execute (#Sql)
But I wish I could do just this:
Declare #PropIDs
Set #PropIDs = '1, 2'
Select PropertyCode
Into #TempProp
From Property where PropertyID IN (#PropIDs)
It is the "...Property IN (#PropIDs)" that is giving me trouble.
Any suggestions?
Create a split table value function similar to this one
create FUNCTION [dbo].[Split](#String varchar(MAX), #Delimiter char(1))
returns #temptable TABLE (items varchar(MAX))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end;
That code is from this question: separate comma separated values and store in table in sql server
Then use it in your query like this:
Declare #PropIDs
Set #PropIDs = '1, 2'
Select PropertyCode
Into #TempProp
From Property where PropertyID IN (dbo.Slit(#PropIDs, ','))

SQL Server Split And Table Insert

I want to do the following using SQL Server 2005.
Create a stored procedure that takes a varchar() comma "," delimited param
Split / Explode the varchar() param and insert the values in a temporary table
Something that will do the following:
INSERT INTO #temp_table SPLIT('john,peter,sally',',');
SELECT * FROM #temp_table;
Is there a function or stored procedure that will perform a split?
If so, how does it work?
Thanks
SQL Server does not have a string split function out of the box, but you can create one like this
CREATE FUNCTION dbo.Split(#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end

Sql Server - pass array to procedure

I need to pass set of int to sql procedure.
alter PROC PrCustomerServicesUpd(
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml NVARCHAR(1000),
#ServicesIdCount INT =1
)
AS
DECLARE #XmlDocHanle INT
EXEC sp_Xml_PrepareDocument #XmlDocHanle OUTPUT, #ServicesIdXml
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT)
EXEC sp_Xml_RemoveDocument #XmlDocHanle
go
PrCustomerServicesUpd '443c293e-fc78-4562-97f8-ee1f2b54f813'
,'<Services><ServiceId>12</ServiceId><ServiceId>156</ServiceId></Services>',22
This script returns one empty field named 'ServiceId' instead of 2 rows.
Assuming this is SQL Server 2000 (otherwise there is no sane reason to use OPENXML), you need to get the text() within the node, otherwise it tries to find the attribute "ServiceId" within the node "ServiceId". Also your parameter XML is completely out of sync with what the proc expects.
alter PROC PrCustomerServicesUpd(
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml NVARCHAR(1000),
#ServicesIdCount INT =1
)
AS
DECLARE #XmlDocHanle INT
EXEC sp_Xml_PrepareDocument #XmlDocHanle OUTPUT, #ServicesIdXml
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT 'text()')
EXEC sp_Xml_RemoveDocument #XmlDocHanle
GO
PrCustomerServicesUpd '443c293e-fc78-4562-97f8-ee1f2b54f813'
,'<ROOT><Services><ServicesId>12</ServicesId><ServicesId>156</ServicesId></Services></ROOT>',3
Using the XML data type
alter PROC PrCustomerServicesUpd
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml xml,
#ServicesIdCount INT =1
AS
select service.id.value('.','int')
from #ServicesIdXml.nodes('/ROOT/Services/ServicesId') service(id)
GO
You can pass set of int in varchar(1000) with comma separator
so int value passing as "1223,12,254,5545,8787,8787,787,78,45475,45,45"
And in store procedure you can get one by one id with fnSplit function (Tabular).
ALTER function [dbo].[fnSplit](
#String nvarchar (4000),
#Delimiter nvarchar (10)
)
returns #ValueTable table ([Value] nvarchar(4000))
begin
declare #NextString nvarchar(4000)
declare #Pos int
declare #NextPos int
declare #CommaCheck nvarchar(1)
--Initialize
set #NextString = ''
set #CommaCheck = right(#String,1)
--Check for trailing Comma, if not exists, INSERT
--if (#CommaCheck <> #Delimiter )
set #String = #String + #Delimiter
--Get position of first Comma
set #Pos = charindex(#Delimiter,#String)
set #NextPos = 1
--Loop while there is still a comma in the String of levels
while (#pos <> 0)
begin
set #NextString = substring(#String,1,#Pos - 1)
insert into #ValueTable ( [Value]) Values (#NextString)
set #String = substring(#String,#pos +1,len(#String))
set #NextPos = #Pos
set #pos = charindex(#Delimiter,#String)
end
return
end
so you can get the one by one value as
"Select value from dbo.fnsplit (#values,',')"
I think you mean ServiceId and not ServicesId.
In addition the third parameter of OPENXML should not be #ServicesIdCount, it should be a value describing what sort of output you want.
Don't think you specify a ROOT node in your XML, so remove that
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT)
should be
SELECT * FROM OPENXML(#XmlDocHanle, '/Services/ServiceId', 1)
WITH (ServiceId INT)

Resources