Input like 111111 and 101,102,103,104
I want to check whether user has access on this requests or not...
I tried a cursor as shown, but I get this error:
Conversion failed when converting the varchar value '101,102,103,104' to data type int.
Code:
ALTER PROCEDURE [dbo].[ValidateRqstId]
#UserID VARCHAR(50),
#RsqtIDs VARCHAR(300)
AS
BEGIN
Declare #RqstId int
Declare #Result int
Declare #UserIDToCheck VARCHAR(50)
Declare #RqstUserVal cursor for
Select RequestId
from REQUEST_LIST
where RequestId in (#RsqtIDs)
BEGIN
OPEN RqstUserVal
FETCH NEXT from RqstUserVal into #RqstId
WHILE(##fetch_status <> -1)
BEGIN
SET #UserIDToCheck = (
select UserId from dbo.REQUEST_LIST where RequestId = #RqstId)
Print(#UserIDToCheck)
If(#UserIDToCheck != #UserID)
SET #Result = 99 ;
--Fetch the next row from the cursor
FETCH RqstUserVal into #RqstId
END
END
CLOSE RqstUserVal
Deallocate RqstUserVal
RETURN #Result
END
Thanks in advance
Depending on your SQL-Server Verion you can use a Table-Valued Function like in this short example
Select * from dbo.test1
Where ID in(
Select * from dbo.F_SplitAsIntTable('1,123,234,456'))
Function defined as
CREATE FUNCTION F_SplitAsIntTable
(
#txt varchar(max)
)
RETURNS
#tab TABLE
(
ID int
)
AS
BEGIN
declare #i int
declare #s varchar(20)
Set #i = CHARINDEX(',',#txt)
While #i>1
begin
set #s = LEFT(#txt,#i-1)
insert into #tab (id) values (#s)
Set #txt=RIGHT(#txt,Len(#txt)-#i)
Set #i = CHARINDEX(',',#txt)
end
insert into #tab (id) values (#txt)
RETURN
END
GO
Related
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?
This is my stored procedure, this is working:
/*
#CRM_Ref - This is the only required input port for this SP
#North_Ref - Output port, returns the North_Ref for a valid CRM_Ref input
#Output_Message - Output port, Returns the output of the SP, either 'Success' or 'North_Ref not found'
*/
ALTER PROCEDURE [dbo].sp_Get_North_Reference
#CRM_Ref NVARCHAR(255),
#North_Ref VARCHAR(255) OUTPUT,
#Output_Message VARCHAR(255) OUTPUT
AS
DECLARE #var_North_Ref VARCHAR(255); -- Variable used to store the North_Ref
DECLARE #var_Output_Message VARCHAR(255); -- Variable to carry the Output_Message
DECLARE #COUNTER INT; -- Counter for the amount of times the while loop should run
SET #COUNTER = 100;
-- Loop will run 10 times with a 10 second delay between each loop
WHILE #COUNTER >= 1
BEGIN
SET #var_North_Ref = (SELECT TOP 1 North_Ref FROM DEV.dbo.Address__ADDRESS WHERE CRM_Ref = #CRM_Ref ORDER BY PUBLICATION_INSTANCE_DATE DESC)
IF #var_North_Ref IS NULL
BEGIN
SET #COUNTER = #COUNTER - 1; -- Counter is decremented by 1
SET #var_Output_Message = 'North_Ref not found';
WAITFOR DELAY '00:00:10'; -- Wait is triggered if no North_Ref is found
END
ELSE
BEGIN
SET #COUNTER = 0; -- Counter is set to 0 to end the while loop
SET #var_Output_Message = 'Success';
END
END
SET #Output_Message = #var_Output_Message; -- Format Output_Message
SET #North_Ref = #var_North_Ref; -- Format North_Ref
;
GO
I would like to add another parameter into this stored procedure (#TableName VARCHAR(255)) which I want to pass to the SELECT statement.
So I would like something like:
SELECT TOP 1 North_Ref
FROM #Table_Name
WHERE CRM_Ref = #CRM_Ref
ORDER BY PUBLICATION_INSTANCE_DATE DESC
I have tried doing this as it is above but I am getting errors as I don't think you can use parameters as a table name in stored procedures
how about try this concept :
CREATE TABLE #tempTable(abc int);
declare #strSQL nvarchar(255)
SET #strSQL = 'insert into #tempTable select 123'
EXEC sp_executesql #strSQL
declare #abc int
select top 1 #abc = abc from #tempTable
drop table #tempTable
select #abc
I have the following (simplified) stored procedure:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo)
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
My problem is, that when FulfilmentID = 4, I wan to add an extra field - 'Delivery'
If have tried the following:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
,Delivery VARCHAR(255)
END
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
DECLARE #_Delivery VARCHAR(255)
END
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo IF #FulfilmentID=4 BEGIN #_Delivery )
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
But this did not work (Please excuse any syntax errors, this is a rough typing for SO)
Form searching the web there does not seem to be much on this. Can it be done?
There are lots of issues in your code:
use SELECT *
use Cursor
...
In the end, it is overly complicated and looks at lot like Application code (C#, java, ...)
What you want to do should be done with a single Select (ie. on a set of data). Columns names should also be listed between SELECT and FROM.
One option is:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS TABLE
AS
RETURN (
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery
FROM VW_FulfilmentExtract_HH
WHERE #FulfilmentID = 4
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_ID
WHERE #FulfilmentID = 3
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Art
WHERE #FulfilmentID = 2
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Tha
WHERE #FulfilmentID = not in (2, 3, 4)
);
Here I use ROW_NUMBER to generate your sequence number.
I added the Delivery column and set it to NULL when it is not needed.
You must update columns name. I just guess them.
By the way, this is not a Stored Procedure but a Inline User-Defined Functions
The following function doesn't return me anything in the colums even if going into debug mode it seams like the values are ok...
can someone help me out?
Obviously the select query on table [NewBiz.Labirinto].dbo.ElencoTipiEsercizio works and returns colums 2 colums:
id | dvr
1 | 1,2,3,4
2 | 1,3
4 | 1,2,4,5,6
USE [NuLab]
GO
/****** Object: UserDefinedFunction [dbo].[fun_CSVToTable] Script Date: 29/01/2015 17:17:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Function [dbo].[fun_CSVToTable]
(
#Delimeter varchar(10)
)
RETURNS #RET1 TABLE (id integer, dvr VARCHAR(50))
AS
BEGIN
DECLARE #RET TABLE(id integer, dvr VARCHAR(50))
DECLARE #RET2 TABLE(id integer, dvr VARCHAR(50))
DECLARE #ID integer
DECLARE #LIST varchar(50)
DECLARE #START BIGINT
DECLARE #LASTSTART BIGINT
DECLARE #VAR integer
set #ID = 0
set #VAR = 1
WHILE(#VAR IS NOT NULL)
BEGIN
IF (#ID > (select MAX(id) from [NewBiz.Labirinto].dbo.ElencoTipiEsercizio)) BREAK
set #LIST=(select dvr from [NewBiz.Labirinto].dbo.ElencoTipiEsercizio where [NewBiz.Labirinto].dbo.ElencoTipiEsercizio.id = #ID)
SET #LASTSTART=0
IF LTRIM(RTRIM(#LIST))='' RETURN
SET #START=CHARINDEX(#Delimeter,#LIST,0)
IF #START=0
INSERT INTO #RET(id, dvr) VALUES(#ID, SUBSTRING(#LIST,0,LEN(#LIST)+1))
WHILE(#START >0)
BEGIN
INSERT INTO #RET(id, dvr) VALUES(#ID, SUBSTRING(#LIST,#LASTSTART,#START-#LASTSTART))
SET #LASTSTART=#START+1
SET #START=CHARINDEX(#Delimeter,#LIST,#START+1)
IF(#START=0)
INSERT INTO #RET(id, dvr) VALUES(#ID, SUBSTRING(#LIST,#LASTSTART,LEN(#LIST)+1))
END
INSERT INTO #RET2 SELECT * FROM #RET
SET #ID = (select min(id) from [NewBiz.Labirinto].dbo.ElencoTipiEsercizio where id > #ID)
END
INSERT INTO #RET1 SELECT * FROM #RET2
RETURN
END
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)