Free memory when using geometry in SQL Server 2008 R2 - sql-server

This text was translated in Google Translate.
When using the geometry functions in SQL Server 2008 R2, I have noticed that my server memory is increasing, and I have no way to release used memory.
I have a table where we store the different polygons that cover the different neighborhoods of my city.
CREATE TABLE dbo.Mapa_MSB (
id int IDENTITY(1, 1) NOT NULL,
zona varchar(50),
GeogCol1 geometry,
GeogCol2 AS [GeogCol1].[STAsText]()
)
So, I have a function whose parameters are the coordinates of a point in my city, and with this it returns the different polygons that point enters. With the coordinates I create my point using geometry::STGeomFromText('POINT(X, Y)', 4326)
declare #geo geometry
declare #flete geometry
declare #result geometry
set #geo = geometry::STGeomFromText('POINT(-100.35171446 25.66744965)', 4326)
Then I make a cursor to read all my polygons from my Mapa_MSB table, and I use the STIntersection function so that it returns me whether or not that point enters that polygon, the result is stored in a temporary memory, and at the end I perform a simple query to obtain the different polygons where there was an intersection.
declare #resultado_temporal table(
resultado varchar(max),
zona varchar(50))
declare #id int,
#zona varchar(50),
#GeogCol1 geometry
declare localiza_cursor cursor for
select id, zona, GeogCol1
from Zonas2.dbo.Mapa_MSB
open localiza_cursor
fetch next from localiza_cursor
into #id, #zona, #GeogCol1
while ##FETCH_STATUS = 0
begin
select #flete = GeogCol1 from Zonas2.dbo.Mapa_MSB where id = #id
set #flete = #flete.MakeValid()
if #flete.STIsValid() = 1
begin
select #result = #flete.STIntersection(#geo)
insert into #resultado_temporal
select #result.STAsText(), #zona
where #result.STAsText() <> 'GEOMETRYCOLLECTION EMPTY'
end
fetch next from localiza_cursor
into #id, #zona, #GeogCol1
end
close localiza_cursor
deallocate localiza_cursor
select * from #resultado_temporal
Every time I use this procedure, the memory of my server is going up, what can I do to optimize this procedure or so that the memory of the server does not go up?

I already managed to optimize the code, I found the book "Beginning Spatial with SQL Server 2008", where they recommend using the Filter() function, so I managed to optimize the code, being like this:
declare #geo geometry
set #geo = geometry::STGeomFromText('POINT(-100.35171446 25.66744965)', 4326)
select GeogCol2, zona
from Zonas2.dbo.Mapa_MSB
where GeogCol1.MakeValid().Filter(#geo) = 1

Related

How to run series of values through stored procedure

I have a stored procedure that I need to run a list of values through and output into a temp table.
This is the SP: EXEC [SP_ReturnHTML] #zoneid, 1
The first value, I assume, will be a variable and the second value will be hard-coded. I am not able to modify this SP, as it is used in other processes, so I need to run these values through the SP via a cursor or WHILE loop. The values only need to be run through once, so a FAST_FORWARD cursor type may be more ideal, based on some preliminary reading on cursors (of which my experience in is extremely limited). This is what I attempted:
declare #zoneid int = (select zoneid from #values)
declare list cursor fast_forward
for EXEC [SP_ReturnHTML] #zoneid,1
open list
fetch next from list
But when I try to do this, I get the error Incorrect syntax near the keyword 'EXEC'.
The output of this SP, when using #zoneid=14105 (and the hard-coded 1 relates to the fieldgroupid) looks something like the shot below. For clarity, despite using #zoneid=14105, the reason a value of 4054 shows up is due to the way the SP is written, and is intended. The two values relate to a state and county relationship, noted by the first 2 columns, ParentHeaderId and HeaderId. I opted to use 14105 for the example, because the 3 examples in the #values table only retrieve their secondary value and I wanted to avoid confusion here.
The values that I need to run through the SP for the #zoneid are in a table (which has about 3100 rows), which can be exemplified with the following:
create table #values (zoneid int)
insert into #values
values
(13346),
(13347),
(13348)
So very simply put, I need something like the following as a final product (pseudo code):
declare #zoneid INT = (select zoneid from #values)
select * into #results from
(
EXEC [SP_ReturnHTML] #zoneid, 1
)
Something like this:
drop table if exists #results
drop table if exists #Data
go
create or alter procedure [SP_ReturnHTML] #value int, #s varchar(20)
as
begin
select concat(' value=',#value, '; s = ', #s)
end
go
create table #Data (value int, county varchar(30))
insert into #Data
values
(100, 'Baker'),
(101,'Baldwin'),
(102,'Baldwin'),
(103,'Ballard'),
(104,'Baltimore City'),
(105,'Baltimore'),
(106,'Bamberg'),
(107,'Bandera'),
(108,'Banders'),
(109,'Banks'),
(110,'Banner'),
(111,'Bannock'),
(112,'Baraga')
go
create table #results(value nvarchar(200))
declare c cursor local for select value from #Data
declare #value int
open c
fetch next from c into #value
while ##fetch_status = 0
begin
insert into #results(value)
EXEC [SP_ReturnHTML] #value, '1'
fetch next from c into #value
end
go
select *
from #results

FOR DO in SQL Server

Just curios can I do this in SQL Server
FOR
SELECT columns
FROM table_name
DO
---do some logic
--proc call
ENDFOR;
which means for every record from first select do something in DO block.
This perfectly works for Ingres DB, but not sure if it will work with SQL Server, or I should use only cursor?
This Syntax is not supported in SQL Server's T-SQL. But - as you mention yourself in your question - there is CURSOR:
--Some *mockup* data
DECLARE #tbl TABLE(ID INT IDENTITY, SomeData VARCHAR(100));
INSERT INTO #tbl VALUES('Row 1'),('Row 2'),('Row 3');
--Declare variables to puffer all row's values
DECLARE #WorkingVariable VARCHAR(100);
--never forget the `ORDER BY` if sort order matters!
DECLARE cur CURSOR FOR SELECT SomeData FROM #tbl ORDER BY ID;
OPEN cur;
--a first fetch outside of the loop
FETCH NEXT FROM cur INTO #WorkingVariable
--loop until nothing more to read
WHILE ##FETCH_STATUS=0
BEGIN
--Do whatever you like with the value(s) read into your variable(s).
SELECT #WorkingVariable;
--Pick the next value
FETCH NEXT FROM cur INTO #WorkingVariable
END
--Don't forget to get rid of the used resources
CLOSE cur;
DEALLOCATE cur;
But please keep in mind, that using a loop (however it is coded) is procedural thinking and against the principles of set-based thinking. There are very rare situations! where a CURSOR (or any other kind of loop) is the right choice...
SQL Server doesn't do any behind-the-scenes work for building WHILE loops.
One way to do something like this in SQL Server would look like:
declare #indexTable table (fieldIndex bigint identity(1,1), field (whatever your type of field is))
insert into #indexTable(field)
select field
from table_name
declare #pointer bigint = 1
declare #maxIndexValue bigint = (select max(fieldIndex) from #indexTable)
declare #fieldValue (fieldtype)
while #pointer <= #maxIndexValue
BEGIN
select #fieldValue = field from #indexTable where fieldIndex = #pointer
---do some logic
--proc call
set #pointer = #pointer + 1
END
This is an alternative to using a cursor to loop over your rowset.

how to use declare variable in select query in stored procedure using sql server

Hello I want to concate two things one is string and other is int variable. Now, these thing I want to store in one variable and use that variable in select query as a into type to create a temptable in stored procedure using sql server.
Here is my query
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, I am talking about these line
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
In these line two things are concate one is string and other is int. And store in varchar variable.
And use in following select query i.e.
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, in these query I want to create a temptable named #tempTable.
But, in these line it showing error i.e. Incorrect syntax near '#tempTable'.
Confuse that where is the syntax is wrong.
Thank You.
There are a number of things wrong with your code.
When concatenating an int to a string, you must first cast the int to varchar. Otherwise, SQL Server will try to implicitly convert the string to int, that will result with an error.
So this: DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID; should become this:
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR(11)); (you need 11 chars to be able to fit the minimum value of int: -2,147,483,648)
You can't use select...into with a table variable.
You can only use it for actual tables (temporary or regular).
your #tempTable isn't even a table variable (not that it will help with a select...into).
Even if you would use select...into the correct way, unless you are going to use a global temporary table (and that doesn't come without it's risks), Unless your stored procedure uses this temporary table later on, it will be useless, since temporary tables are bound to scope.
Taking all of that into consideration I'm not sure what output you are actually looking for. If you could edit your question to include the desired output of your stored procedure as well as some sample data as DDL+DML, it would be easier to help you write better code.
Hope this Dynamic Query helps you:
Try like this:
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR);
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SET #strQuery='
SELECT COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ChapwiseQue
,CASE WHEN COUNT(appQueID)>='+CAST(#PerChapQue AS VARCHAR)+' THEN COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ELSE 1 END ChapWiseQuePlusOne
,appQueChapID
INTO '+#tempTable+'
FROM tblQuestion
WHERE appQueSubID='+CAST(#SubjectID AS VARCHAR)+'
GROUP BY appQueChapID
/*.................................
And you have to use the temp table inside the String only
.................................*/
'
EXEC (#strQuery)
END

Sql Server spatial Find nearest neighbour like in oracle

I'm having a trouble in finding the nearest point in sql server using Long Lat.
I want to pass a longitued and latitude parameter then use it to find the nearest point in that area.
Also is there a way to Select all tables that have a geometry function?
I already found a solution to this problem. This might be helpful to someone.
i already add some optimization to this code. the #Points.STBuffer(1) determine the search distance so i only put 1m because i need a exact long and lat because i get it on click.
ALTER PROCEDURE [dbo].[getFacilityDetailsOnClick]
-- Add the parameters for the stored procedure here
#long float,
#lat float
AS
BEGIN
DECLARE #points geometry
SET #points = geometry :: Point(#long,#lat,32651);
DECLARE #searchArea GEOMETRY;
SET #searchArea = #Points.STBuffer(1);
#tbl nvarchar(255)
SELECT #sSQL = 'SELECT FEATID, NAME , #tbl as FACILITYNAME , #facility as FACILITYID FROM (SELECT TOP 1 featid, NAME , geometry.STDistance(#pnts) as distance from '
+ QUOTENAME(#tbl) +' WHERE geometry.Filter(#searchArea) = 1 ORDER BY distance) AS tbl'
EXEC sp_executesql #sSQL , N'#pnts GEOMETRY , #searchArea GEOMETRY , #tbl nvarchar(255) , #facility int ', #Points , #searchArea , #tbl ,#facility;

TSQL Procedure returning multiple rows of data

I'm busy trying to rewrite some PostgreSQL stored procedures/functions for SQL Server 2014s TSQL.
I am struggling to return my values from this stored procedure though, this one is just a test but I am trying to return multiple rows of data in this case the for the two variables si_code and co_desc.
I have my procedure as follows (as a test)
if (object_id('p_get_serial')) is not null
drop procedure p_get_serial
go
create procedure p_get_serial(#par01 char(20), #par02 integer)
as
declare
#co_num integer,
#co_desc char(20),
#si_code char(20),
#log char(40)
declare mycur cursor for
select co_num, co_desc
from colours
where co_num <= #par02
open mycur
fetch next from mycur into #co_num,
#co_desc
while ##FETCH_STATUS = 0
begin
set #si_code = ''
select #si_code = si_code
from sitems
where si_co_num = #co_num
set #log = #co_desc + ' ' + #si_code
raiserror(#log,0,1) with nowait
fetch next from mycur into #co_num, #co_desc
end
close mycur deallocate mycur
go
exec p_get_serial #par01 = 'paramater01', #par02 = 10
what is the best way to return my results knowing that there will be several rows?
In T-SQL you do not need to declare a cursor. Just select what you need and it will be available to the client app.
Cursor is Oracle/DB2/PostgreSQL etc way of returning data. SQL Server does not need it.
create procedure p
as
select 1 as a
returns a recordset containing one record with one column.
create procedure p
as
select 1 as a, 'a' as b
union select 2, 'b'
returns two rows each with two columns.
Example of a more complex processing before returning a result set:
create procedure p
as
begin
declare #a int, #b varchar(10)
select #a = 1
select #b = convert(varchar(10), #a)
select #a = #a + 1
select #a as a, #b as b -- this will be the resultset returned to the client
end
All you need to do is, just save the data for each row in a temp table or table variable and just write a SELECT statement at the the end of the Stored Procedure.
Your question is not clear what you need exactly, you have a cursor and while loop, they seem to be redundant

Resources