Ok, let's say you have a stored procedure that returns a value.
Now lets say you want to test it in SQL Server Management Studio...
This gives us a value of 1, as expected.
Now if we want to call this from C#, there is a little trick we have to play with Parameters.
Note the trick we had to play here (line 19) to access the return value after the procedure runs. At first, I tried using:
i=myCommand.ExecuteNonQuery();
...but that always yielded a value of -1.
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Saturday, November 19, 2011
Friday, June 17, 2011
Massive ReportViewer Headache Relieved
Ok I like organization. Too much perhaps. But when my project root folder gets full (Microsoft likes everything in there) I get tired of fishing around for all the parts of everything. Did I name that thing reportInventory, ir InventoryReport? So I like to make folders for everything, like so.
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Tuesday, March 29, 2011
Using SQL Server Authentication on SQL Express
For most of my databases, I am content to use Windows Authentication for my database access. In a development or small shop environment, it's usually acceptable to let Windows bear the burden of authentication.
But if you need to add just one database app that requires a separate login beyond the Windows login, here's how.
First a few definitions.
SERVER vs. DATABASE
SQL Server (in my case express 2008 R2) is not a Database. In the management studio, when you log into the management studio, you can see that .\SQLEXPRESS (the root node) is called a server. It is important to read this article carefully when I talk about servers vs. databases, as it makes a difference.
LOGIN vs. USER
This is a little more blurry, but a login is not much more than a name, password, and a set of permissions to access the server. A user exists in databases, and has specific roles and permissions in an individual database.
Getting Started
In the Mode
First, make sure your server is in the mode (mood?) to use both kinds of authentication.
Open SQL Server Management Studio and right-click the SERVER name. Pick properties.
Then on the Security tab, make sure SQL Server and Windows Authentication mode is selected.
If it wasn't, then you'll need to save the change and restart SQL Server. If it was already selected you can skip this section.
Restarting SQL Server
Return to the SQL Server Management Studio and right click the Server Name.
Select restart.
Create a Server Login
When we create logins, in general we want to create one login per user. First, log into management studio using windows authentication (or however you normally gain admin access). Under the server tree (not a database tree) select Security- Logins and pick New Login.
Add your login...
Make sure to add a password and select the default database.
On the User Mapping tab...
Select the checkbox by your database.
Enter dbo as the default schema
Check every permission that doesn't contain the word deny.
Note that there are some additional roles in my database that I had added previously.
On the Status tab, make sure grant and enabled are selected.
Click OK.
Using witch-hazel and fairy dust, Management studio will now create your LOGIN to the SERVER, and your USER in the DATABASE.
Look in the Databases tree and find the user created by the wizard.
Open his properties.
The General tab should look much like this.
Testing
To test your new user/login, open a second copy of SQL Server Management Studio.
Change to SQL Server Authentication and enter your user login info.
If you forgot the password (as I did about 6 times while writing this article) you can go back to the login tree in your first SQL Server Management Studio window and change it there, then try again.
Now it's easy to use this login in your programs to access this database. It's also easy to set database level permissions, roles etc.
in C# to create a connection string to access the database do this:
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
But if you need to add just one database app that requires a separate login beyond the Windows login, here's how.
First a few definitions.
SERVER vs. DATABASE
SQL Server (in my case express 2008 R2) is not a Database. In the management studio, when you log into the management studio, you can see that .\SQLEXPRESS (the root node) is called a server. It is important to read this article carefully when I talk about servers vs. databases, as it makes a difference.
LOGIN vs. USER
This is a little more blurry, but a login is not much more than a name, password, and a set of permissions to access the server. A user exists in databases, and has specific roles and permissions in an individual database.
Getting Started
In the Mode
First, make sure your server is in the mode (mood?) to use both kinds of authentication.
Open SQL Server Management Studio and right-click the SERVER name. Pick properties.
Then on the Security tab, make sure SQL Server and Windows Authentication mode is selected.
If it wasn't, then you'll need to save the change and restart SQL Server. If it was already selected you can skip this section.
Restarting SQL Server
Return to the SQL Server Management Studio and right click the Server Name.
Select restart.
Create a Server Login
When we create logins, in general we want to create one login per user. First, log into management studio using windows authentication (or however you normally gain admin access). Under the server tree (not a database tree) select Security- Logins and pick New Login.
Add your login...
Make sure to add a password and select the default database.
On the User Mapping tab...
Select the checkbox by your database.
Enter dbo as the default schema
Check every permission that doesn't contain the word deny.
Note that there are some additional roles in my database that I had added previously.
On the Status tab, make sure grant and enabled are selected.
Click OK.
Using witch-hazel and fairy dust, Management studio will now create your LOGIN to the SERVER, and your USER in the DATABASE.
Look in the Databases tree and find the user created by the wizard.
Open his properties.
The General tab should look much like this.
Testing
To test your new user/login, open a second copy of SQL Server Management Studio.
Change to SQL Server Authentication and enter your user login info.
If you forgot the password (as I did about 6 times while writing this article) you can go back to the login tree in your first SQL Server Management Studio window and change it there, then try again.
Now it's easy to use this login in your programs to access this database. It's also easy to set database level permissions, roles etc.
in C# to create a connection string to access the database do this:
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Thursday, March 3, 2011
SQL Server 2008 R2 Express
Three Hours later...
What a bunch of USELESS CRAP!
For those who lack a life, the text in the box below is...
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
What a bunch of USELESS CRAP!
For those who lack a life, the text in the box below is...
The following notes apply to this release of SQL Server only.And the log file it left says
Microsoft Update
For information about how to use Microsoft Update to identify updates for SQL Server 2008 R2, see the Microsoft Update Web site at http://go.microsoft.com/fwlink/?LinkId=108409.
Samples
By default, sample databases and sample code are not installed as part of SQL Server Setup. To install sample databases and sample code for non-Express editions of SQL Server 2008 R2, see the CodePlex Web site at http://go.microsoft.com/fwlink/?LinkId=87843. To read about support for SQL Server sample databases and sample code for SQL Server Express, see Databases and Samples Overview on the CodePlex Web site at http://go.microsoft.com/fwlink/?LinkId=110391.
Release Notes
For more information about late-breaking changes in this release of SQL Server, see the latest readme file at http://go.microsoft.com/fwlink/?LinkId=141691.
Documentation and Links
To install the .NET Framework SDK, see “Installing the .NET Framework SDK” in SQL Server 2008 R2 Books Online at http://go.microsoft.com/fwlink/?LinkId=141693.
For information about SQL Server 2008 R2 Surface Area Configuration, see the following SQL Server 2008 R2 documentation topics:
In SQL Server 2008 R2 Books Online: “Understanding Surface Area Configuration.”
In SQL Server 2008 R2 Setup Help: “Minimize SQL Server 2008 R2 Surface Area.”
In SQL Server 2008 R2 Books Online on MSDN: Understanding Surface Area Configuration at http://go.microsoft.com/fwlink/?LinkId=141692.
Overall summary:
Final result: Failed: see details below
Exit code (Decimal): -2068052398
Exit facility code: 1212
Exit error code: 1618
Exit message: Failed: see details below
Start time: 2011-03-03 15:55:52
End time: 2011-03-03 16:52:14
Requested action: Upgrade
Log with failure: C:\Program Files\Microsoft SQL Server\100\Setup Bootstrap\Log\20110303_155335\sql_engine_core_inst_ctp6_Cpu32_1.log
Exception help link: http://go.microsoft.com/fwlink?LinkId=20476&ProdName=Microsoft+SQL+Server&EvtSrc=setup.rll&EvtID=50000&ProdVer=10.50.1600.1
Machine Properties:
Machine name: WEB1
Machine processor count: 2
OS version: Windows Server 2003
OS service pack: Service Pack 2
OS region: United States
OS language: English (United States)
OS architecture: x86
Process architecture: 32 Bit
OS clustered: No
Product features discovered:
Product Instance Instance ID Feature Language Edition Version Clustered
Sql Server 2008 SQLEXPRESS MSSQL10.SQLEXPRESS Database Engine Services 1033 Express Edition 10.1.2531.0 No
Sql Server 2008 SQLEXPRESS MSSQL10.SQLEXPRESS SQL Server Replication 1033 Express Edition 10.1.2531.0 No
Sql Server 2008 Management Tools - Basic 1033 Express Edition 10.0.1600.22 No
Package properties:
Description: SQL Server Database Services 2008 R2
ProductName: SQL Server 2008 R2
Type: RTM
Version: 10
SPLevel: 0
Installation location: d:\bf7ec28684b1818f6c3151c67288a7c8\x86\setup\
Installation edition: EXPRESS_ADVANCED
User Input Settings:
ACTION: Upgrade
AGTDOMAINGROUP: <empty>
BROWSERSVCSTARTUPTYPE: Automatic
CONFIGURATIONFILE:
CUSOURCE:
ENU: True
ERRORREPORTING: False
FAILOVERCLUSTERROLLOWNERSHIP: 2
FARMACCOUNT: <empty>
FARMADMINPORT: 0
FARMPASSWORD: *****
FTSVCACCOUNT: <empty>
FTSVCPASSWORD: *****
FTUPGRADEOPTION: Import
HELP: False
IACCEPTSQLSERVERLICENSETERMS: False
INDICATEPROGRESS: False
INSTANCEID: SQLEXPRESS
INSTANCENAME: SQLEXPRESS
ISSVCACCOUNT: NT AUTHORITY\NetworkService
ISSVCPASSWORD: *****
ISSVCSTARTUPTYPE: Automatic
PASSPHRASE: *****
PCUSOURCE:
PID: *****
QUIET: False
QUIETSIMPLE: False
RSCATALOGSERVERINSTANCENAME: Unknown
RSUPGRADEDATABASEACCOUNT:
RSUPGRADEPASSWORD: *****
SQLDOMAINGROUP: <empty>
SQMREPORTING: True
UIMODE: AutoAdvance
X86: False
Configuration file: C:\Program Files\Microsoft SQL Server\100\Setup Bootstrap\Log\20110303_155335\ConfigurationFile.ini
Detailed results:
Feature: Database Engine Services
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Client Connectivity
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Client Connectivity SDK
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Writer
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Browser
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Server Replication
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: SQL Compact Edition Runtime
Status: Passed
MSI status: Passed
Configuration status: Passed
Feature: Management Tools - Basic
Status: Passed
MSI status: Passed
Configuration status: Passed
Rules with failures:
Global rules:
Scenario specific rules:
Rules report file: C:\Program Files\Microsoft SQL Server\100\Setup Bootstrap\Log\20110303_155335\SystemConfigurationCheck_Report.htm
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Tuesday, February 22, 2011
SQL Server Money Type Conversion
How to convert a SQL Server money Type to a C# floating point number.
The easiest way yo do this is to use the C# decimal type.
I had tried double and float, and they both gave me an explicit conversion error.
FYI: when initializing a decimal, use this:
Think of the "m" as "money".
In format strings, use {0:C} (currency format) to display.
Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
The easiest way yo do this is to use the C# decimal type.
decimal amount = (decimal)myReader["Amount"];I had tried double and float, and they both gave me an explicit conversion error.
FYI: when initializing a decimal, use this:
decimal mynumber=0m;Think of the "m" as "money".
In format strings, use {0:C} (currency format) to display.
string.format("{0:C}",amount);Bryan Valencia is a contributing editor and founder of Visual Studio Journey. He owns and operates Software Services, a web design and hosting company in Manteca, California.
Friday, March 12, 2010
General SQL Optimization Tips and Tricks
SQL and You
SQL can get complicated. You are simple. That's just the way it is.
You like issuing commands like...
...when all you need is a few columns. But the SQL Server will
dutifully fetch all the data you requested, no matter the cost to the
performance of the server, the network, and your fellow database users.
The above query might not be too bad, but when you see what an order
looks like...
...you figure out you need to join in some additional data to make a
meaningful report.
so you join to the customer table, and your query becomes:
...giving us a concatenated name...

Ok, time goes on and you add joins to categorize the orders by state,
product type, salesman, etc. etc. etc. until your SQL gets into a state
we like to call gnarly. Another thing that happens is that your
SQL is written to make life easier for you, not for the database
server. Soon, your query gives you the perfect data, and your
report/web site/whatever looks amazing - after minutes of crunching to
gather the data.
This article is written to help you find and correct some common things
that make queries easy for us, but difficult for your database server.
This process in general, is called query optimization and
companies pay big bucks for people who are experts at this. Imagine a
business with 800 users entering data on their desktops. Some are on
the phone with vendors or clients, and system performance is mission
critical. Suddenly you launch off the un-optimized query for your
weekly TPS report, and the entire database starts chugging like The Little Engine That Could.
This means hundreds of your business
clients all start hearing words like "Geez, hang on - this screen is
loading...". You can see the business need here.
Even if your business is small, why tax your systems needlessly if you
can take a few steps to write better SQL that gives you the data you
need faster? I promise - if your small business grows big, that query
that generates a report out of your 1MB database in 3 seconds now will
probably take 30 seconds when you reach 10MB and 5 minutes at 100MB.
Tip 1: Never use Select *
Select * is great for when you just want to get a feel for what data is
in a table. But it's the least efficient thing you can do in a
production query. Think about it. First, the parser has to access the
data dictionary and fetch the names and types of all the columns in the
table (or multiple, joined tables). Then your '*' is replaced with all
the names of the columns - which (by the way) are not guaranteed to be
in any particular order under ANSI SQL specs. If you are writing a
query for production use, one that will potentially execute thousands of
times a day, take the time to tell it which columns to return.
Tip 2: Indexes
Indexes are designed to help queries. If you're summarizing sales by
agent, then adding a secondary index to the agent column in your sales
table will save you a lot of time. Technically the time is being spent,
but it's being used in tiny slices whenever you change data in the
sales table. That triggers the maintenance of the index, which can then
be searched much faster than the whole table.
Tip 3: Case Insensitive Searches
Consider:
This query might work, unless you're looking for all people who entered
any of these: McHenry, mchenry, Mchenry, MCHENRY, McHENRY. ok - so you
want to just find the customers with a case insensitive search. So you
do this:
What happens now? The query is executed not against the field "lastname"
(and any indexes applied to it), it is instead executed against the
function lowercase(), which has no index. There are two
common workable solutions to this issue. Neither of the solutions is
to make sure all data is entered using strict capitalization
standards. No one wants to be the Capitalization Nazi!
Tip 4: Data Warehousing
Sometimes you just *must* have that report that performs a 23 table join
against a 40 million record database. There's just no way you can put
out your TPS reports without it. What many companies do is perform
certain data mining and harvesting tasks once per day, rolling up and
summarizing certain data into a "data warehouse" for offline reporting
needs. This data is often de-normalized to make faster queries and it's
usually stored on a different database server and even a different
network to prevent reporting from slowing down the workday.
The idea is that you create a query that performs certain common joins
and relations... rolls up hourly/daily/monthly or whatever kind of
totals, creates various types of crosstabs, and stores the rolled up
data in a reporting database.
These summaries are run during off hours (or infrequently during the
workday) to prevent the database servers from clogging with work while
you're open for business.
Managers and their lackeys can hammer away at the reporting database all
day long and your main operation could not care less.
Tip 5: Joins vs. Sub-Selects
Sometimes when you just want a single lookup from a table (say decoding a
County ID to a name) , it's faster to not join in the county table.
Some SQL servers can detect this kind of lookup and perform this
optimization for you. Note...
We have joined the aspnet_UsersInRoles table to get the ROLEID of the
user's roles, and joined the aspnet_Roles table to get the name of the
roles for the user.
Note the difference here:
See how we're using the sub-select to pick up one field? The thing
about this tip is that sometimes the former way is faster and sometimes
the latter. You have to experiment.
Tip 6: Explain Plan/Query Optimizers
Ok, most SQL Servers have a module called a Query Optimizer. This
module can take your weak, human SQL and tweak it before execution to
improve performance. But there is also usually a UI that you can use to
performance tune your queries. I know Oracle has this, and have used
it many times. It breaks your query up into chunks called a query
plan, and assigns an estimated cost to each part of the
plan. You can then alter the text of your query to improve the overall
performance.
Tip 7: Query Hints
On the rare occasions when your SQL is tricking the optimizer into
taking the wrong approach to your query, Oracle and SQL Server have the
ability for you to add query hints to your SQL. These hints can
tell the optimizer to use a specific kind of cursor, or prefer a
different index, and alter the query plan used during execution.
The syntax differs greatly between the various SQL servers
(Oracle/MSSQL/etc.), and will be shown only as an example here.
Tip 8: Views
Sometimes creating a view can help optimize your query. The idea is to
optimize the SQL for certain common transactions and save it as a view,
making the need to reinvent the wheel significantly lower. But there is
also such a thing as a materialized view. This is a type of view
that is maintained like an index, as the live data is stored in the
main tables. A normal view does not store it's own data, but a
materialized view does. The view's data can then be queried without
having to do whatever complex joins were needed to generate the data.
Of course the trade-off here is storage space.
SQL can get complicated. You are simple. That's just the way it is.
You like issuing commands like...
select * from orders
...when all you need is a few columns. But the SQL Server will
dutifully fetch all the data you requested, no matter the cost to the
performance of the server, the network, and your fellow database users.
The above query might not be too bad, but when you see what an order
looks like...
...you figure out you need to join in some additional data to make a
meaningful report.
so you join to the customer table, and your query becomes:
select o.*, b.billto_firstname+' '+b.billto_lastname as CustName from orders o
join buyerdata b on b.OrderID = o.OrderID
...giving us a concatenated name...

Ok, time goes on and you add joins to categorize the orders by state,
product type, salesman, etc. etc. etc. until your SQL gets into a state
we like to call gnarly. Another thing that happens is that your
SQL is written to make life easier for you, not for the database
server. Soon, your query gives you the perfect data, and your
report/web site/whatever looks amazing - after minutes of crunching to
gather the data.
This article is written to help you find and correct some common things
that make queries easy for us, but difficult for your database server.
This process in general, is called query optimization and
companies pay big bucks for people who are experts at this. Imagine a
business with 800 users entering data on their desktops. Some are on
the phone with vendors or clients, and system performance is mission
critical. Suddenly you launch off the un-optimized query for your
weekly TPS report, and the entire database starts chugging like The Little Engine That Could.
clients all start hearing words like "Geez, hang on - this screen is
loading...". You can see the business need here.
Even if your business is small, why tax your systems needlessly if you
can take a few steps to write better SQL that gives you the data you
need faster? I promise - if your small business grows big, that query
that generates a report out of your 1MB database in 3 seconds now will
probably take 30 seconds when you reach 10MB and 5 minutes at 100MB.
Tip 1: Never use Select *
Select * is great for when you just want to get a feel for what data is
in a table. But it's the least efficient thing you can do in a
production query. Think about it. First, the parser has to access the
data dictionary and fetch the names and types of all the columns in the
table (or multiple, joined tables). Then your '*' is replaced with all
the names of the columns - which (by the way) are not guaranteed to be
in any particular order under ANSI SQL specs. If you are writing a
query for production use, one that will potentially execute thousands of
times a day, take the time to tell it which columns to return.
Tip 2: Indexes
Indexes are designed to help queries. If you're summarizing sales by
agent, then adding a secondary index to the agent column in your sales
table will save you a lot of time. Technically the time is being spent,
but it's being used in tiny slices whenever you change data in the
sales table. That triggers the maintenance of the index, which can then
be searched much faster than the whole table.
Tip 3: Case Insensitive Searches
Consider:
Select fname, lname, email from Customers where lastname='McHenry'
This query might work, unless you're looking for all people who entered
any of these: McHenry, mchenry, Mchenry, MCHENRY, McHENRY. ok - so you
want to just find the customers with a case insensitive search. So you
do this:
Select fname, lname, email from Customers where lowercase(lastname)=lowercase(@searchname)
What happens now? The query is executed not against the field "lastname"
(and any indexes applied to it), it is instead executed against the
function lowercase(), which has no index. There are two
common workable solutions to this issue. Neither of the solutions is
to make sure all data is entered using strict capitalization
standards. No one wants to be the Capitalization Nazi!
- Use a function index. Oracle supports these. you can actually make
an index on "lowercase(field)" or "getmonth(datefield)". This is not a
widespread feature, but is really useful in these cases. - Add a lower or upper column in your data to use for joining and
searching. If you have an ASP.NET membership provider database, note
that the aspnet_users table has a column named LoweredUserName.
If this approach is good enough for Microsoft, it's good enough for me.
Tip 4: Data Warehousing
Sometimes you just *must* have that report that performs a 23 table join
against a 40 million record database. There's just no way you can put
out your TPS reports without it. What many companies do is perform
certain data mining and harvesting tasks once per day, rolling up and
summarizing certain data into a "data warehouse" for offline reporting
needs. This data is often de-normalized to make faster queries and it's
usually stored on a different database server and even a different
network to prevent reporting from slowing down the workday.
The idea is that you create a query that performs certain common joins
and relations... rolls up hourly/daily/monthly or whatever kind of
totals, creates various types of crosstabs, and stores the rolled up
data in a reporting database.
These summaries are run during off hours (or infrequently during the
workday) to prevent the database servers from clogging with work while
you're open for business.
Managers and their lackeys can hammer away at the reporting database all
day long and your main operation could not care less.
Tip 5: Joins vs. Sub-Selects
Sometimes when you just want a single lookup from a table (say decoding a
County ID to a name) , it's faster to not join in the county table.
Some SQL servers can detect this kind of lookup and perform this
optimization for you. Note...
select U.UserName, RR.RoleName from aspnet_Users U
join aspnet_UsersInRoles R on R.UserId=U.UserId
join aspnet_Roles RR on RR.RoleId=R.RoleId
We have joined the aspnet_UsersInRoles table to get the ROLEID of the
user's roles, and joined the aspnet_Roles table to get the name of the
roles for the user.
Note the difference here:
select U.UserName,
(select RR.RoleName from aspnet_Roles RR where RR.RoleId=R.RoleId) as Role
from aspnet_Users U
join aspnet_UsersInRoles R on R.UserId=U.UserId
See how we're using the sub-select to pick up one field? The thing
about this tip is that sometimes the former way is faster and sometimes
the latter. You have to experiment.
Tip 6: Explain Plan/Query Optimizers
Ok, most SQL Servers have a module called a Query Optimizer. This
module can take your weak, human SQL and tweak it before execution to
improve performance. But there is also usually a UI that you can use to
performance tune your queries. I know Oracle has this, and have used
it many times. It breaks your query up into chunks called a query
plan, and assigns an estimated cost to each part of the
plan. You can then alter the text of your query to improve the overall
performance.
Tip 7: Query Hints
On the rare occasions when your SQL is tricking the optimizer into
taking the wrong approach to your query, Oracle and SQL Server have the
ability for you to add query hints to your SQL. These hints can
tell the optimizer to use a specific kind of cursor, or prefer a
different index, and alter the query plan used during execution.
The syntax differs greatly between the various SQL servers
(Oracle/MSSQL/etc.), and will be shown only as an example here.
Tip 8: Views
Sometimes creating a view can help optimize your query. The idea is to
optimize the SQL for certain common transactions and save it as a view,
making the need to reinvent the wheel significantly lower. But there is
also such a thing as a materialized view. This is a type of view
that is maintained like an index, as the live data is stored in the
main tables. A normal view does not store it's own data, but a
materialized view does. The view's data can then be queried without
having to do whatever complex joins were needed to generate the data.
Of course the trade-off here is storage space.
Wednesday, December 16, 2009
Using MSSQL to Calculate Map Distances
This procedure will show you how to create a SQL Server function that accepts 2 map coordinates in and calculates the surface distance between them.
First we will create the function.
So now we have a function to accept two lat/long coords and return the distance. To use it in a select, (assuming you have a data table of geodata organized by zip code, like this... Access Zip Code Database.
Import this data to SQL Server and then use this select statement.
Note here that the data as presented in the Access table stores the latitudes and longitudes as text, so we need to use cast to force it to floats. This gives us a result set that looks a lot like this...
First we will create the function.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Bryan Valencia
-- Create date: 12/16/2009
-- Description: takes latitude/longitude for 2
-- places on Earth and gives the spherical distance.
-- =============================================
DROP FUNCTION Geo_Distance
GO
CREATE FUNCTION Geo_Distance
(
@lat1 float,
@long1 float,
@lat2 float,
@long2 float
)
RETURNS float
AS
BEGIN
DECLARE @r float
--radius of the Earth
--select @r=3437.74677 --(nautical miles)
--select @r=6378.7 --(kilometers)
SELECT @r=3963.0 --(statute miles)
--radians
DECLARE @radlat1 float
DECLARE @radlong1 float
DECLARE @radlat2 float
DECLARE @radlong2 float
SELECT @radlat1 = RADIANS(@lat1)
SELECT @radlong1 = RADIANS(@long1)
SELECT @radlat2 = RADIANS(@lat2)
SELECT @radlong2 = RADIANS(@long2)
--calculate answer (from http://www.sqlteam.com/article/intro-to-user-defined-functions-updated)
-- and http://www.meridianworlddata.com/Distance-Calculation.asp
DECLARE @answer float
SELECT @answer = @r * ACOS(SIN(@radlat1)*SIN(@radlat2)+COS(@radlat1)*COS(@radlat2)*cos(@radlong2 - @radlong1))
RETURN @answer
END
GO
So now we have a function to accept two lat/long coords and return the distance. To use it in a select, (assuming you have a data table of geodata organized by zip code, like this... Access Zip Code Database.
Import this data to SQL Server and then use this select statement.
Select distinct Z1.[ZIP Code], Z1.City, Z1.[State Code],
dbo.Geo_Distance(
cast(Z2.Latitude as float),cast(Z2.Longitude as float),
cast(Z1.Latitude as float),cast(Z1.Longitude as float)) as Distance
from [ZIP Codes] Z1
left outer join [ZIP Codes] Z2 on (Z2.[ZIP Code]='94558')
order by 4
Note here that the data as presented in the Access table stores the latitudes and longitudes as text, so we need to use cast to force it to floats. This gives us a result set that looks a lot like this...
Subscribe to:
Posts (Atom)
How to Auto-generate Order Line Item numbers for bulk uploads
I had a problem where I had 17000 line items to insert into 9000 orders. The system required line item numbers, preferably numbered 1throug...
-
I had a problem where I had 17000 line items to insert into 9000 orders. The system required line item numbers, preferably numbered 1throug...
-
This article explains how to copy a database from one server to another when Backup/Restore is not an option. This will work as long as...
-
Ok I like organization. Too much perhaps. But when my project root folder gets full (Microsoft likes everything in there) I get tired of ...













