Is there a scalar database variable in SQL Server? - sql-server

We are creating a schema version for our database. Right now we have a database table with a column version and a single row with the version.
Is it possible to make a scalar variable on the database, rather than a table?
Something like:
SET DBNAME.dbo.DBVersion = 1;

You may consider to store a scalar value in an Extended Property attached to your database.
To add an extended property use sp_addextendedproperty
EXEC sp_addextendedproperty #name = N'DBVersion', #value = '1';
To get a value of your property fn_listextendedproperty
SELECT value FROM fn_listextendedproperty(N'DBVersion', default, default, default, default, default, default);
Output:
Value
-----
1
Further reading:
Using Extended Properties on Database Objects

When I need to store constant values somewhere in the database for that that’s not necessarily related I usually end up with dbo.Config table that has one column for each cost that it needs to hold.
If you really want to store this somewhere outside the table you can consider extended properties, views, functions or stored procedures.
You can always create a function that looks like
CREATE FUNCTION dbo.GetSomeConst ()
RETURNS int
BEGIN
return 12
END

For static (read-only) data, you can also define a single-row view:
CREATE VIEW V_Constants AS
SELECT '1' AS DBVersion
as sketched in an earlier answer

Related

SQL Server - How do i get multiple rows of data into a returned variable

First question here so hoping that someone can help!
Im doing a lot of conversions of Access backends on to SQL server, keeping the front end in Access.
I have come across something that i need a little help with.
In Access, I have a query that is using a user-defined function in order to amalgamate some data from rows in a table into one variable. (By opening a recordset and enumerating through, adding to a variable each time.)
For example:
The query has a field that calls the function like this:
ProductNames: Product(ContractID)
And the VBA function "Product()" searches a table based on the ContractID. Cycles through each row it finds and concatenates the results of one field into one variable, ultimately returned to the query.
Obviously, moving this query to SQL server as a view means that that function will not be found as its in Access.
Can I use a function or stored procedure in order to do the same thing? (I have never used them before)
I must stress that I cannot create, alter or drop tables at run-time due to very strict production environment security.
If someone could give me an example id be really grateful.
So i need to be able to call it from the view as shown above.
Let say the table im looking at for the data is called tbl_Products and it has 2 columns:
| ContractID | Product |
How would that be done?! any help massively appreciated!
Andy
Yes you can most certainly do the same thing and adopt the same approach in SQL like you did in the past with VBA + SQL.
The easy solution would be to link to the view, and then build a local query that adds the additional column. However, often for reasons of performance and simply converting sql from Access to T-SQL, then I often “duplicate” those VBA functions as T-SQL functions.
The beauty of this approach is once you make this function, then this goes a “long” way towards easy converting some of your Access SQL to t-sql and views.
I had a GST calculation function in VBA that you would pass the amount, and a date (because the gst rate changes at a known date (in the past, or future).
So I used this function all over the place in my Access SQL.
When I had to convert to sql server, then I was able to use “views” and pass-though quires from Access and simply use “very” similar sql and include that sql function in the sql just like I did in Access.
You need to create what is called a SQL function. This function is often called a scaler function. This function works just like a function in VBA.
So in t-sql store procedure, or even as a expression in your SQL just like in Access!!!!
In your example, lets assume that you have some contract table, and you want to grab the “status” column (we assume text).
And there could be one, 1 or “several” or none!.
So we will concatenate each of the child records “status” code based on contract id.
You can thus fire up SSMS and in the database simply expand your database in the tree view. Now expand “programmability”. Now expand functions. You see “scaler-valued functions”. These functions are just like VBA functions. Once created, you can use the function in code (t-sql) or in views etc.
At this point, you can now write t-sql code in place of VBA code.
And really, you don’t have to “expand” the tree above – but it will allow you to “find” and “see” and “change” your functions you create. Once created then ANY sql, or code for that database can use the function as a expression just like you did in Access.
This code should do the trick:
CREATE FUNCTION [dbo].[ContractStatus]
(#ContractID int)
RETURNS varchar(255)
AS
BEGIN
-- Declare a cursor (recordset)
DECLARE #tmpStatus varchar(25)
DECLARE #MyResult varchar(255)
set #MyResult = ''
DECLARE rst CURSOR
FOR select Status from tblContracts where ID = #ContractID
OPEN rst
FETCH NEXT FROM rst INTO #tmpStatus
WHILE ##FETCH_STATUS = 0
BEGIN
IF #MyResult <> ''
SET #MyResult = #MyResult + ','
SET #MyResult = #MyResult + #tmpStatus
FETCH NEXT FROM rst INTO #tmpStatus
END
-- Return the result of the function
RETURN #MyResult
END
Now, in sql, you can go:
Select ProjectName, ID, dbo.ProjectStatus([ID]) as MyStatus from tblProjects.

Why are table valued parameters to SQL Server stored procedures required to be input READONLY?

Can anyone explain the design decision behind preventing table valued parameters from being specified as output parameters to stored procedures?
I can't count the number of times I've started building out a data model hoping to completely lock down my tables to external access (you know...implementation details), grant applications access to the database through stored procedures only (you know... the data interface) and communicate back and forth with TVPs only to have SSMS call me naughty for having the audacity to think that I can use a user-defined table type as the transfer object between my data service and my application.
So someone please provide me a good reason why TVPs were designed to be readonly input parameters.
In the presentation on Optimizing Microsoft SQL Server 2008 Applications Using Table Valued Parameters, XML, and MERGE by Michael Rys he says. (at 32:52)
Note that in SQL Server 2008 table valued parameters are read only.
But as you notice we actually require you to write READONLY. So that
actually then means that at some point in the future maybe if you say
please, please please often enough we might be able to actually make
them writable as well at some point. But at the moment they are read
only.
Here is the connect item you should use to add your "please". Relax restriction that table parameters must be readonly when SPs call each other.
Srini Acharya made a comment on the connect item.
Allowing table valued parameters to be read/write involves quite a bit
of work on the SQL Engine side as well as client protocols. Due to
time/resource constraints as well as other priorirites, we will not be
able to take up this work as part of SQL Server 2008 release. However,
we have investigated this issue and have this firmly in our radar to
address as part of the next release of SQL Server.
Table-valued parameters have the following restrictions(source MSDN):
SQL Server does not maintain statistics on columns of table-valued
parameters.
Table-valued parameters must be passed as input READONLY
parameters to Transact-SQL routines. You cannot perform DML
operations such as UPDATE, DELETE, or INSERT on a table-valued
parameter in the body of a routine.
You cannot use a table-valued parameter as target of a SELECT INTO
or INSERT EXEC statement. A table-valued parameter can be in the
FROM clause of SELECT INTO or in the INSERT EXEC string or stored
procedure.
there are few options to over come this restriction one is
CREATE TYPE RTableType AS TABLE(id INT, NAME VARCHAR )
go
CREATE PROCEDURE Rproc #Rtable RTABLETYPE READONLY,
#id INT
AS
BEGIN
SELECT *
FROM #Rtable
WHERE ID = #id
END
go
DECLARE #Rtable RTABLETYPE
DECLARE #Otable RTABLETYPE
INSERT INTO #Rtable
VALUES (1,'a'),
(2,'b')
INSERT #Otable
EXEC Rproc
#Rtable,
2
SELECT *
FROM #Otable
through this you can get the table values out
With respect to (emphasis added):
So someone please provide me a good reason why TVPs were designed to be readonly input parameters.
I just posted a more detailed answer to this on DBA.StackExchange here:
READONLY parameters and TVP restrictions
But the summary of it goes like this:
According to this blog post ( TSQL Basics II - Parameter Passing Semantics ), a design goal of Stored Procedure OUTPUT parameters is that they merely mimic "by reference" behavior when the Stored Procedure completes successfully! But when there is an error that causes the Stored Procedure to abort, then any changes made to any OUTPUT parameters would not be reflected in the current value of those variables upon control returning to the calling process.
But when TVPs were introduced, they implemented them as truly passing by reference since continuing the "by value" model -- in which a copy of it is made to ensure that changes are lost if the Stored Procedure does not complete successfully -- would not be efficient / scalable, especially if a lot of data is being passed in through TVP.
So there is only one instance of the Table Variable that is the TVP, and any changes made to it within any Stored Procedure (if they were not restricted to being READONLY) would be immediately persisted and would remain, even if the Stored Procedure encountered an error. This violates the design goal stated at the beginning of this summary. And, there is no option for somehow tying changes made to a TVP to a transaction (even something handled automatically, behind the scenes) since table variables are not bound by transactions.
Hence, marking them as READONLY is the only way (at the moment) to maintain the design goal of Stored Procedure parameters such that they do not reflect changes made within the Stored Procedure unless: the parameter is declared as OUTPUT and the Stored Procedure complete successfully.
Be Forewarned. This code will not work. That is the problem
Note that all code was entered directly into post from memory. I may have a type wrong in the example or some similar error. It is just to demonstrate the technique that this would facilitate, which won't work with any version of SQL Server released at the time of this writing. So it doesn't really matter if it currently compiles or not.
I know this question is old by now, but perhaps someone coming across my post here might benefit from understanding why it's a big deal that TVPs can't be directly manipulated by a stored proc and read as output parameters by the calling client.
"How do you..." questions regarding OUTPUT TVPs have littered SQL Server forums for more than half a decade now. Nearly every one of them involves someone attempting some supposed workaround that completely misses the point of the question in the first place.
It is entirely non sequitur that you can "get a result set that matches a table type" by creating a Table Typed variable, Inserting into it and then returning a read from it. When you do that, the result set is still not a message. It is an ad hoc ResultSet that contains arbitrary columns that "just happen to match" a UDTT. What is needed is the ability for the following:
create database [Test]
create schema [Request]
create schema [Response]
create schema [Resources]
create schema [Services]
create schema [Metadata]
create table [Resources].[Foo] ( [Value] [varchar](max) NOT NULL, [CreatedBy] [varchar](max) NOT NULL) ON [PRIMARY]
insert into [Resources].[Foo] values("Bar", "kalanbates");
create type [Request].[Message] AS TABLE([Value] [varchar](max) NOT NULL)
create type [Response].[Message] AS TABLE([Resource] [varchar](max) NOT NULL, [Creator] [varchar](max) NOT NULL, [LastAccessedOn] [datetime] NOT NULL)
create PROCEDURE [Services].[GetResources]
(#request [Request].[Message] READONLY, #response [response].[Message] OUTPUT)
AS
insert into #response
select [Resource].[Value] [Resource]
,[Resource].[CreatedBy] [Creator]
,GETDATE() [LastAccessedOn]
inner join #request as [Request] on [Resource].[Value] = [Request].[Value]
GO
and have an ADO.NET client be able to say:
public IEnumerable<Resource> GetResources(IEnumerable<string> request)
{
using(SqlConnection connection = new SqlConnection("Server=blahdeblah;database=Test;notGoingToFillOutRestOfConnString")
{
connection.Open();
using(SqlCommand command = connection.CreateCommand())
{
command.CommandText = "[Services].[GetResources]"
command.CommandType = CommandType.StoredProcedure;
SqlParameter _request;
_request = command.Parameters.Add(new SqlParameter("#request","[request].[Message]");
_request.Value = CreateRequest(request,_request.TypeName);
_request.SqlDbType = SqlDbType.Structured;
SqlParameter response = new SqlParameter("#response", "[response].[Message]"){Direction = ParameterDirection.Output};
command.Parameters.Add(response);
command.ExecuteNonQuery();
return Materializer.Create<List<ResourceEntity>>(response).AsEnumerable(); //or something to that effect.
//The point is, messages are sent to and received from the database.
//The "result set" contained within response is not dynamic. It has a structure that can be *reliably* anticipated.
}
}
}
private static IEnumerable<SqlDataRecord> CreateRequest(IEnumerable<string> values, string typeName)
{
//Optimally,
//1)Call database stored procedure that executes a select against the information_schema to retrieve type metadata for "typeName", or something similar
//2)Build out SqlDataRecord from returned MetaData
//Suboptimally, hard code "[request].[Message]" metadata into a SqlMetaData collection
//for example purposes.
SqlMetaData[] metaData = new SqlMetaData[1];
metaData[0] = new SqlMetaData("Value", SqlDbType.Varchar);
SqlDataRecord record = new SqlDataRecord(metaData);
foreach(string value in values)
{
record.SetString(0,value);
yield return record;
}
}
The point here is that with this structure, the Database defines [Response].[Message],[Request].[Message], and [Services].[GetResource] as its Service Interface. Calling clients interact with "GetResource" by sending a pre-determined message type and receive their response in a pre-determined message type. Of course it can be approximated with an XML output parameter, you can somewhat infer a pre-determined message type by instituting tribal requirements that retrieval stored procedures must insert its response into a local [Response].[Message] Table Typed variable and then select directly out of it to return its results. But none of those techniques are nearly as elegant as a structure where a stored procedure fills a response "envelope" provided by the client with its payload and sends it back.
Still in 2020, SQL version "Microsoft SQL Azure (RTM) - 12.0.2000.8", I am not able to edit the Table value parameter within the Stored Procedure. So I did the work around by moving the data into Temp table and edited it.
ALTER PROCEDURE [dbo].[SP_APPLY_CHANGESET_MDTST09_MSG_LANG]
#CHANGESET AS [dbo].[MDTSTYPE09_MSG_LANG] READONLY
AS
BEGIN
SELECT * INTO #TCHANGESET FROM #CHANGESET
UPDATE #TCHANGESET SET DTST08_MSG_K = 0 WHERE ....
...............

Setting multiple variables from a Execute SQL Task result object with a single row

I have the following sql in an EXECUTE SQL TASK:
SELECT [CnxnStrValue1] as INT_Support_CnxnStr
,[CnxnStrValue2] as Lawson_CnxnStr
,[CnxnStrValue3] as Lawson_HRIS_CnxnStr
FROM [dbo].[InterfaceDBCnxn]
WHERE InterfaceName = ?
The result set is set to an object variable. I also have three string variables to hold the values and typically I would map them to a For Each Loop Container. But, in this case, my result set will always only be one row because InterfaceName is the primary key of the table.
Whats is the best way to set the variables with out using a for each loop container?
Change your result set from Full to Single Row. I use this pattern for my DW loads to get the surrogate key value for my unknown members.
ResultSet set to Single row
Map your parameters as needed. Here, I have 8 variables that get mapped
Given your table is Table and a column is Column_name and Column_name_two you can do something like this.
SELECT #yourVar = Column_name,
#yourSecondVar = Column_name_two
FROM Table
WHERE Table_id = 1

How does Visual Studio dataset designer work when creating table adapter based on procedure

I need to update dataset table adapter in Visual Studio 2010. It is based on a stored procedure. The store procedure has parameters
#IDportfolio INT
, #Date varchar(50) = NULL
, #IDorder int = NULL
, #IDsession nvarchar(300) = NULL
, #User varchar(100) = NULL
, #UDNsXML NVARCHAR(MAX) = NULL
, #DEBUG INT = 0
The table adapter had this methods:
Fill,GetData (#IDportfolio, #Date, #IDorder, #IDsession, #User, #UDN)
So I needed to refresh it. In the procedure there is one IF statement that gets executed only if #DEBUG is set to 1. Inside this IF statement there are some SELECT statements used for internal debugging. Value 1 is obviously not default value as can be seen in the signature, yet designer, when refreshing the methods, acts like it is sending value 1 for #DEBUG parameter.
So instead of returning values that should be returned, it returns wrong set of values, and designer tries to make methods based on these returned values.
Why is designer working like that and is there some default value for INT parameters, or is he ignoring default values? I have noticed similar behavior in Entity Framework too.
OK well the (VS) designer needs to determine the sent values (parameters) and the returned values (columns and data types). (to generate associated classes). It uses what could loosely be called reflection. To do this the stored procedure must conform to certain rules, there are 4 i've discovered, off the top of my head, here are the important 3:
Only one row set can be returned (this is explicitly stated by MS somewhere)
The row set must be persistent outside the stored procedure i.e. it cant come from a table variable. (this is explicitly stated by MS somewhere)
It must be deterministic. (this is explicitly stated by MS somewhere)
Using a debug parameter, which the calling softwaer will never set to 1 will allow you to run the proc for testing and return various value at different points in the stored procedure. However for the VS designer, because these rows are not (by defualt) returned, the proc will still behave when analysed by VS.

Is there any way I can execute this SPROC and get the result with Entity Framework?

This SPROC "returns" a table with two columns: Id, Score.
Is it possible to execute this SPROC and include the custom data-type as parameters from within Entity Framework?
ALTER PROCEDURE [presenta].[SearchLpi]
// The presenta.IdTableType is a table with just one column "Id"
#selectedLpis presenta.IdTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
WITH Scores AS(
SELECT
ItemId, SUM(Score) AS Score
FROM [Presenta].[presenta].[LpivScores]
WHERE
ListPropertyItemId IN (
SELECT Id
FROM #selectedLpis
)
GROUP BY
ItemId
)
SELECT
i.Id,
s.Score
FROM
Scores s,
Items i
WHERE
s.ItemId = i.Id
END
If not, is there any other way to get the results of the SPROC and being able to join this result with another LINQ-query?
Here you are better of writing a EF linq query directly against the table. See http://msdn.microsoft.com/en-us/library/bb896341.aspx for an example.
If you must use stored procedures, then there is a way using a table as a return type. You need to create a temporary table with the fields that you return. See: http://blogs.msdn.com/bindeshv/archive/2008/11/20/using-stored-procedures-in-entity-framework.aspx
This is one of the areas where EF 4 will bring a substantial improvement. With EF4, you'll be able to pull in a stored procedure, and if the return value of that sproc doesn't map to a given table, you can easily create a so-called complex type (basically a class) that will hold the stored proc return values.
See some blog posts for samples and more info on that:
Automatic Generation of Stored Procedure Return Types
Using a Stored Procedure in Entity Framework 4
A big step for Stored Procedures in EF4
Getting Started with Entity Framework 4 – Complex Types and Entities
Yet another great new feature to look forward to!
Create DefiningQuery in the Store part of the model with properties corresponding to the result of your stored procedure.
You can make it using XML Editor you like. Devart Entity Developer has design-time support for DefiningQueries.
Then create a function import for the procedure and set the return type to the hand-made entity.
Devart Team
http://www.devart.com/dotconnect
ADO.NET data providers for Oracle, MySQL, PostgreSQL, SQLite with
Entity Framework and LINQ to SQL support

Resources