How to pass value to stored procedure with spatial/geography data type using SQL query - sql

I'm a student and after 2H searching answer I'm hopping that someone can help me here.
I created a stored procedure that expects a name, address and geography location then adds a new branch to the Branches table. I'm trying to pass a geography value using a new query, but I keep getting a syntax error.
Stored procedure :
create procedure AddBranch
#Name nvarchar(50),
#Address nvarchar(100),
#GeographicLocation geography
as
begin
SET NOCOUNT ON
insert into Branches (Name, Address, GeographicLocation)
values (#Name, #Address, #GeographicLocation)
select BranchID
from Branches
where BranchID = SCOPE_IDENTITY()
end
Query:
exec AddBranch
#Name = 'Some Name',
#Address = 'Some Address',
#GeographicLocation = geography::Point(47.65100, -122.34900, 4326)
Error:
Incorrect syntax near'::'
Is there a way to pass geography data to a stored procedure?

In addition to enclosing the arguments in quotes, you need to assign the method result to a local variable in order to pass the value as a parameter in T-SQL:
DECLARE #geographyPoint geography = geography::Point('47.65100', '-122.34900', '4326');
exec AddBranch
#Name = 'Some Name',
#Address = 'Some Address',
#GeographicLocation = #geographyPoint;

as a sidenote:
create procedure dbo.AddBranch --always specify schema
#Name nvarchar(50),
#Address nvarchar(100),
#GeographicLocation geography
as
begin
SET NOCOUNT ON
SET XACT_ABORT ON --should be in every data modification SP
insert into dbo.Branches (Name, Address, GeographicLocation) --schema!
output inserted.BranchID --this
values (#Name, #Address, #GeographicLocation)
select SCOPE_IDENTITY() BranchID --or this
--absolutely no need in another read operation from persistent table
end

Put the values into quotes like this
exec AddBranch
#Name = 'Some Name',#Address = 'Some Address',
#GeographicLocation = geography::Point('47.65100', '-122.34900', '4326')
go
Although this might not work depending on how this custom Geography type expects its values, it will solve the syntax error.

Related

Stored Proc returns 2 return values

I have a stored proc that first checks if an entry exists and if so updates it then returns the row ID, if not it inserts a new record then returns the row ID.
When executing the stored proc I am given 2 return values, one with the field '#PersonID' and the other with 'Return Value'. I'm pretty sure this is happening because of the SELECT statement that is used in the IF EXISTS, however, I'm unable to figure a way to suppress it and I was hoping someone could help.
ALTER PROCEDURE [dbo].[InsertPerson]
-- Add the parameters for the stored procedure here
#FirstName nvarchar(50),
#LastName nvarchar(50),
#PersonID int OUT
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF( EXISTS (SELECT PersonID FROM People
WHERE FirstName = #FirstName AND LastName = #LastName))
BEGIN
SET #PersonID = (SELECT PersonID
FROM People
WHERE FirstName = #FirstName
AND LastName = #LastName)
UPDATE People
SET
FirstName = #FirstName,
LastName = #LastName
WHERE PersonID = #PersonID
END
ELSE
BEGIN
INSERT INTO People (FirstName, LastName) VALUES(#FirstName, #LastName)
SET #PersonID = SCOPE_IDENTITY()
SELECT #PersonID
END
Thanks for the quick responses. I had accidently posted some incorrect code, the actual stored proc doesn't have SELECT #PersonID at the end. However, I think I have incorrectly identified the stored proc as the root cause of the issue I'm working on and as pointed out in the responses everything is working as expected.
Thanks again for the help

SQL. Trying to create a stored procedure on SQL, but not sure if I have the right query

Create a SQL stored procedure that parses a string into previously unknown number of fields. The inputs would be
a text string of undetermined length;
a delimiter, passed as a string;
a nullable column that, if relevant, would pass the text indicator as a single character string.
The resulting table would be entirely dependent on the string used as an input
Please help because I cannot figure this out. I know this is wrong, but I had no clue where to begin.
Here is what I have tried so far:
DECLARE #l INT, #c VARCHAR(MAX) = ''
SELECT #l = MAX(LEN(n)) FROM AdventureWOrk
DECLARE #s NVARCHAR(MAX) = '
;WITH cte AS
)
Insert INTO #Values (1, 'CGID', 'EENumber', 'EEYID', 'SSN' )
SELECT
[Value],
[Value],
Prod_Attributes.value('/Attribute[1]','varchar(MAX)') AS [CGID],
Prod_Attributes.value('/Attribute[2]','varchar(MAX)') AS [EENUMBER],
Prod_Attributes.value('/Attribute[3]','varchar(MAX') AS [EYEID],
Prod_Attributes.value('/Attribute[4]','varchar(MAX') AS [SSN]
You can create a stored procedure by using the following syntax:
CREATE PROCEDURE usp_YourProcedure
AS
BEGIN
-- Your logic
END
You would put the code you already have within the BEGIN statement.
To execute the stored procedure you can do:
EXEC usp_YourProcedure
To add parameters, simply state them after the CREATE PROCEDURE declaration.
CREATE PROCEDURE usp_YourProcedure
(
#TextField VARCHAR(MAX),
#Delimeter VARCHAR(1),
#TextIndicator CHAR(1) = NULL
)
AS
BEGIN
END
Then to execute with parameters:
EXEC usp_YourProcedure 'String literal, with commas, which will, be stripped out by the delimiter', ','
Further details are outlined at MSDN.
As an additional note, try keeping your variable names descriptive and consistent, also check the casing.
CREATE PROCEDURE <ProcedureName>
-- Add the parameters for the stored procedure here
<Param1>, <Param2> ...
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
END
GO

Extract parameters from a table of parameters in a stored procedure?

I defined the next Data Type:
CREATE TYPE dbo.FieldsTable AS TABLE
(
[Name] nvarchar(255),
[Value] nvarchar(255)
)
I want to declare a stored procedure with this sign:
CREATE PROCEDURE dbo.uspSaveEntity
(
#Id int,
#Fields [FieldsTable] readonly
)
AS
...
This procedure should receive a FieldsTable type with the list of fields and values that I need to set in the UPDATE of the entity.
For example, to call the procedure I want to do somnething like:
DECLARE #entityFields FieldsTable;
INSERT INTO #entityFields VALUES ('FirstName', 'John');
INSERT INTO #entityFields VALUES ('LastName', 'Doe');
EXEC uspSaveEntity 1500, #entityFields
The question is: How I can extract the parameters from the table I receive?
Until now I was thinking in something like:
SET #FirstName = (SELECT Value FROM #Fields WHERE Name = 'FirstName');
SET #LastName = (SELECT Value FROM #Fields WHERE Name = 'LastName');
...
UPDATE tblEntity SET FirstName = #FirstName ...
I think using SET and SELECT for each field is too much code maybe... exist some approche more clear to do this?
The UPDATE query and all the stored procedure dont need to be dynamic, but needs to support have this particular way to receive parameters.
The individual set statements are quite reasonable. An alternative would be a pivot or conditional aggregation:
select #FirstName = max(case when Name = 'FirstName' then Value end),
#LastName = max(case when Name = 'LastName' then Value end),
. . .
from #Fields;
The table you have is a local table and rows count I suspect is very little. So from performance view every solution will be identical. I would prefer the solution which is more readable in this case. You can directly select values in variables in select without using set statements:
SELECT #FirstName = Value FROM #Fields WHERE Name = 'FirstName';

Dynamic update of string values in tables using Stored procedure

The following is my stored procedure to update a column in SQL SERVER
ALTER PROCEDURE [dbo].[AspPageUpdate]
(#type varchar(50),#comp varchar(50),
#place varchar(50))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #tid varchar;
DECLARE #ph int;
SET #ph = CAST(#place AS int);
select #tid = Type_Id
from TypeTable
where Type_Name = #type
UPDATE TypeSetupTable
SET PLACE_HOLDERS = #ph
WHERE complexity = #comp
AND Type_Id = #tid
END
But the table is not getting updated. I think the problem is with Quotes(Strings need to be in quotes, right?).
If i'm giving static values, it is execting, like:
UPDATE TypeSetupTable SET PLACE_HOLDERS = #ph WHERE complexity = 'Simple' AND Type_Id = 'SSRS'
Please tell me a solution.
Thanks in Advance.
you didn't set the size of the variable #tid.
Are you sure of the content of that variable while executing the stored procedure?
Try to put a raiserror(#tid,15,1) and check the content of that variable.
There are blogs about the habit not to size varchar variables.
It is also officially documented that the size of unsized varchars is 1.

How to select xml in 1 stored procedure and pass selected nodes as parameters into another procedure

I have a stored proc that does inserts of “people”. I have an xml document with a bunch of people I want to insert. I want to call my stored proc like below and expect the stored proc to be called for each person in the xml. It is telling me that the stored proc “expects a parameter of #Id” and is failing. #Id is the first param and it appears that my syntax is not allowed. Is there a way to do this without iterating over each person in a cursor? I am using SQL Server 2005.
EXEC Stored_Procedure_That_Inserts_People
SELECT Node.value('Id[1]', 'Int') AS Id
,Node.value('FirstName[1]', 'varchar(50)') AS FirstName
,Node.value('LastName[1]', 'varchar(50)') AS LastName
,Node.value('MI[1]', 'char(1)') AS MI
FROM #PeopleXML.nodes('/ArrayOfPeople/Person') TempXML (Node)
For anybody interested, this is how I implemented my solution based on Tom's answer below:
CREATE PROCEDURE [dbo].[ccIU_PersonBulkImport]
(
#PersonXML as xml
)
AS
BEGIN
SET NOCOUNT ON
DECLARE
#LastName AS varchar(50),
#FirstName AS varchar(50),
#MI AS char(1)
DECLARE People CURSOR FORWARD_ONLY STATIC READ_ONLY FOR
SELECT
Node.value('FirstName[1]', 'varchar(50)') AS FirstName
,Node.value('LastName[1]', 'varchar(50)') AS LastName
,Node.value('MI[1]', 'char(1)') AS MI
FROM #PersonXML.nodes('/ArrayOfPeople/Person') TempXML (Node)
OPEN People;
FETCH NEXT FROM People INTO #FirstName,#LastName,#MI
WHILE (##FETCH_STATUS = 0)
BEGIN
EXEC domIU_People #FirstName,#LastName,#MI -- second stored proc that inserts or updates the person
FETCH NEXT FROM People INTO #FirstName,#LastName,#MI;
END
CLOSE People;
DEALLOCATE People;
END
No.
You cant iterate a stored procedure like that generally they can only take objects as parameters the exception being a table object.
In this example SQL will try and call the SP and then run the select as separate events which is why you are getting the error about the missing parameter.
Your choices are to iterate through the XML and call the SP for each record, refactor the SP to either work using the XML as a separate parameter and break it down in the insert people procedure or refactor the code from the sp into the XML handling logic procedure.
If the stored procedure is a simple insert into the People table then you could create a new stored procedure such as:
CREATE PROCEDURE dbo.Insert_People_From_XML
#people_xml XML
AS
BEGIN
INSERT INTO dbo.People
(
id,
first_name,
last_name,
middle_initial
)
SELECT
Node.value('Id[1]', 'Int'),
Node.value('FirstName[1]', 'varchar(50)'),
Node.value('LastName[1]', 'varchar(50)'),
Node.value('MI[1]', 'char(1)')
FROM
#people_xml.nodes('/ArrayOfPeople/Person') TempXML (Node)
END
If you have business logic (or other logic that you don't want to duplicate) then you may want to reuse your insert stored procedure as it is. In that case, you will have to iterate through the XML nodes. As much as I try to avoid cursors, this would be a time to use one:
DECLARE
#id INT,
#first_name VARCHAR(50),
#last_name VARCHAR(50),
#middle_initial CHAR(1)
DECLARE people_cursor CURSOR FOR
SELECT
Node.value('Id[1]', 'Int'),
Node.value('FirstName[1]', 'varchar(50)'),
Node.value('LastName[1]', 'varchar(50)'),
Node.value('MI[1]', 'char(1)')
FROM
#people_xml.nodes('/ArrayOfPeople/Person') TempXML (Node)
OPEN people_cursor
FETCH NEXT FROM people_cursor INTO #id, #first_name, #last_name, #middle_initial
WHILE (##FETCH_STATUS = 0)
BEGIN
EXEC Your_Proc
#id = #id,
#first_name = #first_name,
#last_name = #last_name,
#middle_initial = #middle_initial
FETCH NEXT FROM people_cursor INTO #id, #first_name, #last_name, #middle_initial
END
CLOSE people_cursor
DEALLOCATE people_cursor
NOTE: This was all written off the top of my head. I don't use XML much, so syntax may need to be corrected, you'll want to add error-handling, etc.