Insert default value when parameter is null - sql

I have a table that has a column with a default value:
create table t (
value varchar(50) default ('something')
)
I'm using a stored procedure to insert values into this table:
create procedure t_insert (
#value varchar(50) = null
)
as
insert into t (value) values (#value)
The question is, how do I get it to use the default when #value is null? I tried:
insert into t (value) values ( isnull(#value, default) )
That obviously didn't work. Also tried a case statement, but that didn't fair well either. Any other suggestions? Am I going about this the wrong way?
Update: I'm trying to accomplish this without having to:
maintain the default value in multiple places, and
use multiple insert statements.
If this isn't possible, well I guess I'll just have to live with it. It just seems that something this should be attainable.
Note: my actual table has more than one column. I was just quickly writing an example.

Christophe,
The default value on a column is only applied if you don't specify the column in the INSERT statement.
Since you're explicitiy listing the column in your insert statement, and explicity setting it to NULL, that's overriding the default value for that column
What you need to do is "if a null is passed into your sproc then don't attempt to insert for that column".
This is a quick and nasty example of how to do that with some dynamic sql.
Create a table with some columns with default values...
CREATE TABLE myTable (
always VARCHAR(50),
value1 VARCHAR(50) DEFAULT ('defaultcol1'),
value2 VARCHAR(50) DEFAULT ('defaultcol2'),
value3 VARCHAR(50) DEFAULT ('defaultcol3')
)
Create a SPROC that dynamically builds and executes your insert statement based on input params
ALTER PROCEDURE t_insert (
#always VARCHAR(50),
#value1 VARCHAR(50) = NULL,
#value2 VARCHAR(50) = NULL,
#value3 VARCAHR(50) = NULL
)
AS
BEGIN
DECLARE #insertpart VARCHAR(500)
DECLARE #valuepart VARCHAR(500)
SET #insertpart = 'INSERT INTO myTable ('
SET #valuepart = 'VALUES ('
IF #value1 IS NOT NULL
BEGIN
SET #insertpart = #insertpart + 'value1,'
SET #valuepart = #valuepart + '''' + #value1 + ''', '
END
IF #value2 IS NOT NULL
BEGIN
SET #insertpart = #insertpart + 'value2,'
SET #valuepart = #valuepart + '''' + #value2 + ''', '
END
IF #value3 IS NOT NULL
BEGIN
SET #insertpart = #insertpart + 'value3,'
SET #valuepart = #valuepart + '''' + #value3 + ''', '
END
SET #insertpart = #insertpart + 'always) '
SET #valuepart = #valuepart + + '''' + #always + ''')'
--print #insertpart + #valuepart
EXEC (#insertpart + #valuepart)
END
The following 2 commands should give you an example of what you want as your outputs...
EXEC t_insert 'alwaysvalue'
SELECT * FROM myTable
EXEC t_insert 'alwaysvalue', 'val1'
SELECT * FROM myTable
EXEC t_insert 'alwaysvalue', 'val1', 'val2', 'val3'
SELECT * FROM myTable
I know this is a very convoluted way of doing what you need to do.
You could probably equally select the default value from the InformationSchema for the relevant columns but to be honest, I might consider just adding the default value to param at the top of the procedure

Try an if statement ...
if #value is null
insert into t (value) values (default)
else
insert into t (value) values (#value)

As far as I know, the default value is only inserted when you don't specify a value in the insert statement. So, for example, you'd need to do something like the following in a table with three fields (value2 being defaulted)
INSERT INTO t (value1, value3) VALUES ('value1', 'value3')
And then value2 would be defaulted. Maybe someone will chime in on how to accomplish this for a table with a single field.

Probably not the most performance friendly way, but you could create a scalar function that pulls from the information schema with the table and column name, and then call that using the isnull logic you tried earlier:
CREATE FUNCTION GetDefaultValue
(
#TableName VARCHAR(200),
#ColumnName VARCHAR(200)
)
RETURNS VARCHAR(200)
AS
BEGIN
-- you'd probably want to have different functions for different data types if
-- you go this route
RETURN (SELECT TOP 1 REPLACE(REPLACE(REPLACE(COLUMN_DEFAULT, '(', ''), ')', ''), '''', '')
FROM information_schema.columns
WHERE table_name = #TableName AND column_name = #ColumnName)
END
GO
And then call it like this:
INSERT INTO t (value) VALUES ( ISNULL(#value, SELECT dbo.GetDefaultValue('t', 'value') )

This is the best I can come up with. It prevents sql injection uses only one insert statement and can ge extended with more case statements.
CREATE PROCEDURE t_insert ( #value varchar(50) = null )
as
DECLARE #sQuery NVARCHAR (MAX);
SET #sQuery = N'
insert into __t (value) values ( '+
CASE WHEN #value IS NULL THEN ' default ' ELSE ' #value ' END +' );';
EXEC sp_executesql
#stmt = #sQuery,
#params = N'#value varchar(50)',
#value = #value;
GO

chrisofspades,
As far as I know that behavior is not compatible with the way the db engine works,
but there is a simple (i don't know if elegant, but performant) solution to achive your two objectives of DO NOT
maintain the default value in multiple places, and
use multiple insert statements.
The solution is to use two fields, one nullable for insert, and other one calculated to selections:
CREATE TABLE t (
insValue VARCHAR(50) NULL
, selValue AS ISNULL(insValue, 'something')
)
DECLARE #d VARCHAR(10)
INSERT INTO t (insValue) VALUES (#d) -- null
SELECT selValue FROM t
This method even let You centralize the management of business defaults in a parameter table, placing an ad hoc function to do this, vg changing:
selValue AS ISNULL(insValue, 'something')
for
selValue AS ISNULL(insValue, **getDef(t,1)**)
I hope this helps.

The best option by far is to create an INSTEAD OF INSERT trigger for your table, removing the default values from your table, and moving them into the trigger.
This will look like the following:
create trigger dbo.OnInsertIntoT
ON TablenameT
INSTEAD OF INSERT
AS
insert into TablenameT
select
IsNull(column1 ,<default_value>)
,IsNull(column2 ,<default_value>)
...
from inserted
This makes it work NO MATTER what code tries to insert NULLs into your table, avoids stored procedures, is completely transparent, and you only need to maintain your default values in one place, namely this trigger.

You can use default values for the parameters of stored procedures:
CREATE PROCEDURE MyTestProcedure ( #MyParam1 INT,
#MyParam2 VARCHAR(20) = ‘ABC’,
#MyParam3 INT = NULL)
AS
BEGIN
-- Procedure body here
END
If #MyParam2 is not supplied, it will have the 'ABC' value...

You can use the COALESCE function in MS SQL.
INSERT INTO t ( value ) VALUES( COALESCE(#value, 'something') )
Personally, I'm not crazy about this solution as it is a maintenance nightmare if you want to change the default value.
My preference would be Mitchel Sellers proposal, but that doesn't work in MS SQL. Can't speak to other SQL dbms.

Don't specify the column or value when inserting and the DEFAULT constaint's value will be substituted for the missing value.
I don't know how this would work in a single column table. I mean: it would, but it wouldn't be very useful.

Hope To help to -newbie as i am- Ones who uses Upsert statements in MSSQL.. (This code i used in my project on MSSQL 2008 R2 and works simply perfect..May be It's not Best Practise.. Execution time statistics shows execution time as 15 milliSeconds with insert statement)
Just set your column's "Default value or binding" field as what you decide to use as default value for your column and Also set the column as Not accept null values from design menu and create this stored Proc..
`USE [YourTable]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[YourTableName]
#Value smallint,
#Value1 bigint,
#Value2 varchar(50),
#Value3 varchar(20),
#Value4 varchar(20),
#Value5 date,
#Value6 varchar(50),
#Value7 tinyint,
#Value8 tinyint,
#Value9 varchar(20),
#Value10 varchar(20),
#Value11 varchar(250),
#Value12 tinyint,
#Value13 varbinary(max)
-- in my project #Value13 is a photo column which storing as byte array..
--And i planned to use a default photo when there is no photo passed
--to sp to store in db..
AS
--SET NOCOUNT ON
IF #Value = 0 BEGIN
INSERT INTO YourTableName (
[TableColumn1],
[TableColumn2],
[TableColumn3],
[TableColumn4],
[TableColumn5],
[TableColumn6],
[TableColumn7],
[TableColumn8],
[TableColumn9],
[TableColumn10],
[TableColumn11],
[TableColumn12],
[TableColumn13]
)
VALUES (
#Value1,
#Value2,
#Value3,
#Value4,
#Value5,
#Value6,
#Value7,
#Value8,
#Value9,
#Value10,
#Value11,
#Value12,
default
)
SELECT SCOPE_IDENTITY() As InsertedID
END
ELSE BEGIN
UPDATE YourTableName SET
[TableColumn1] = #Value1,
[TableColumn2] = #Value2,
[TableColumn3] = #Value3,
[TableColumn4] = #Value4,
[TableColumn5] = #Value5,
[TableColumn6] = #Value6,
[TableColumn7] = #Value7,
[TableColumn8] = #Value8,
[TableColumn9] = #Value9,
[TableColumn10] = #Value10,
[TableColumn11] = #Value11,
[TableColumn12] = #Value12,
[TableColumn13] = #Value13
WHERE [TableColumn] = #Value
END
GO`

With enough defaults on a table, you can simply say:
INSERT t DEFAULT VALUES
Note that this is quite an unlikely case, however.
I've only had to use it once in a production environment. We had two closely related tables, and needed to guarantee that neither table had the same UniqueID, so we had a separate table which just had an identity column, and the best way to insert into it was with the syntax above.

The most succinct solution I could come up with is to follow the insert with an update for the column with the default:
IF OBJECT_ID('tempdb..#mytest') IS NOT NULL DROP TABLE #mytest
CREATE TABLE #mytest(f1 INT DEFAULT(1), f2 INT)
INSERT INTO #mytest(f1,f2) VALUES (NULL,2)
INSERT INTO #mytest(f1,f2) VALUES (3,3)
UPDATE #mytest SET f1 = DEFAULT WHERE f1 IS NULL
SELECT * FROM #mytest

The pattern I generally use is to create the row without the columns that have default constraints, then update the columns to replace the default values with supplied values (if not null).
Assuming col1 is the primary key and col4 and col5 have a default contraint
-- create initial row with default values
insert table1 (col1, col2, col3)
values (#col1, #col2, #col3)
-- update default values, if supplied
update table1
set col4 = isnull(#col4, col4),
col5 = isnull(#col5, col5)
where col1 = #col1
If you want the actual values defaulted into the table ...
-- create initial row with default values
insert table1 (col1, col2, col3)
values (#col1, #col2, #col3)
-- create a container to hold the values actually inserted into the table
declare #inserted table (col4 datetime, col5 varchar(50))
-- update default values, if supplied
update table1
set col4 = isnull(#col4, col4),
col5 = isnull(#col5, col5)
output inserted.col4, inserted.col5 into #inserted (col4, col5)
where col1 = #col1
-- get the values defaulted into the table (optional)
select #col4 = col4, #col5 = col5 from #inserted
Cheers...

The easiest way to do this is to modify the table declaration to be
CREATE TABLE Demo
(
MyColumn VARCHAR(10) NOT NULL DEFAULT 'Me'
)
Now, in your stored procedure you can do something like.
CREATE PROCEDURE InsertDemo
#MyColumn VARCHAR(10) = null
AS
INSERT INTO Demo (MyColumn) VALUES(#MyColumn)
However, this method ONLY works if you can't have a null, otherwise, your stored procedure would have to use a different form of insert to trigger a default.

The questioner needs to learn the difference between an empty value provided and null.
Others have posted the right basic answer: A provided value, including a null, is something and therefore it's used. Default ONLY provides a value when none is provided. But the real problem here is lack of understanding of the value of null.
.

Related

Looping over columns and changing Null values

I have a table called myTable where some values are null.
I want to replace all null values in all columns with the previous non null value. I found some code that iterates over each row for a specific column, and changes Null Values as I want.
DECLARE #value AS int
UPDATE myTable
SET
#value = COALESCE(col2, #value),
col2 = COALESCE(col2, #value)
Result:
This does what I want it do do but only for one column at the time. My goal is to alter the code above in some way so that I can automatically loop over each column in the table.
I ran into several issues when trying to achieve this. Here is my attempt
DECLARE #ColNames table (NAMES nvarchar(50), ARRAYINDEX int identity(1,1) )
INSERT INTO #ColNames (NAMES)
VALUES ('col1'),('col2'),('col3')
DECLARE #INDEXVAR int
DECLARE #TOTALCOUNT int
SET #INDEXVAR = 0
SELECT #TOTALCOUNT = COUNT(*) FROM #ColNames
WHILE #INDEXVAR < #TOTALCOUNT
BEGIN
DECLARE #curColName nvarchar (50)
SELECT #INDEXVAR = #INDEXVAR + 1
SELECT #curColName = NAMES from #ColNames where ARRAYINDEX = #INDEXVAR
DECLARE #value AS int
UPDATE myTable
SET
#value = COALESCE(#curColName, #value),
#curColName = COALESCE(#curColName, #value)
END
The issues that I have found and not been able to solve are the following:
#curColName is just a nvarchar variable and not a representation of my actual column, even if the names are the same. This gives me errors on both lines inside the SET statement.
When hard coding the column names in my loop inside the BEGIN/END statement., the script fills out ALL Null values with a number. So col2 gets the value 3 on ALL rows, not only row 2 and 3 as my previous example.
If these two points are hard or impossible to solve, is there an easier way of solving this problem?
Thanks
This is based on your expected results, and that you actually want to assign the value of Col2 to be the value of the previous non-NULL value, when ordered by the column pk.
If so, to achieve this you can use an updatable CTE. The first CTE puts the data into groups, based on the non-NULL values, and then the second gets the MAX value of Col2 in the group (which would be the non-NULL value). Finally you UPDATE against that CTE on rows where Col2 has the value NULL:
CREATE TABLE dbo.YourTable (PK int,
Col1 int,
Col2 int);
INSERT INTO dbo.YourTable (PK,Col1,Col2)
VALUES(1,2,NULL),
(2,NULL,3),
(3,NULL,NULL);
GO
WITH Groups AS(
SELECT Col2,
COUNT(Col2) OVER (ORDER BY PK) AS Grp
FROM dbo.YourTable),
Maxes AS(
SELECT Col2,
MAX(Col2) OVER (PARTITION BY Grp) AS MaxCol2
FROM Groups)
UPDATE Maxes
SET Col2 = MaxCol2
WHERE Col2 IS NULL;
GO
SELECT *
FROM dbo.YourTable;
GO
DROP TABLE dbo.YourTable;

Updating field containing single ` (backtick) with a NULL

I am trying to import data from a source that I have no control of the data quality. I know how to remove/replace most anything but I have encountered a field that contains a single ` (backtick), I need to replace this with a NULL. I am needing to remove the backtick because I convert the data from the varchar field that it is to a numeric. I have tried versions of this:
Update dbo.Sale
Set Stamps = NULL
where Stamps = ''''
You can use CHAR(39) for clarity's sake:
UPDATE dbo.Sale
SET Stamps = NULL
WHERE Stamps = CHAR(39);
this may help you
DECLARE #t TABLE (MyColumn VARCHAR(255))
INSERT INTO #t
( MyColumn )
VALUES ( '''' -- MyColumn - varchar(255)
)
SELECT *
FROM #t
UPDATE #t
SET MyColumn = NULL
WHERE MyColumn = CHAR(39)
SELECT *
FROM #t
OR
UPDATE #t
SET MyColumn = NULL
WHERE MyColumn = ''''

Temporary table using Transact sql

I'm beginner to T-SQL, I have this issue: I'd like to use a temporary table without creating it, so I wrote this stored procedure :
create PROCEDURE [dbo].[proc_Affaires_By_Client]
#clt_nom varchar(255) ,
#cmd_numero varchar(10),
#etap_cmd_libelle varchar(50),
#typ_cmd_libelle varchar(50)
AS
Begin
DECLARE #temp_tbl_proc TABLE (cmd_code_pk int NOT NULL,
clt_nom varchar(255) NOT NULL,
cmd_nom varchar(100) NOT NULL,
etap_cmd_libelle varchar(50) NULL,
DateAncienTS DateTime NULL,
DateTecentTS DateTime NULL,
TotalHeure numeric(3,2) not null,
TotalHeurePerid numeric(3,2) not null
);
INSERT INTO #temp_tbl_proc(cmd_code_pk, clt_nom, cmd_numero, cmd_nom, etap_cmd_libelle, typ_cmd_libelle, DateAncienTS, DateTecentTS, TotalHeure, TotalHeurePerid)
SELECT
ISNULL(cmd_code_pk, 1) AS cmd_code_pk, clt_nom, cmd_numero,
cmd_nom, etap_cmd_libelle, typ_cmd_libelle,
CONVERT(datetime, '01/01/1900', 103) AS DateAncienTS,
CONVERT(datetime, '01/01/1900', 103) AS DateTecentTS,
-1.00 AS TotalHeure, -1.00 AS TotalHeurePerid
FROM
OPENQUERY(SAB, 'SELECT c.cmd_code_pk, cl.clt_nom, c.cmd_numero, c.cmd_nom,et.etap_cmd_libelle,ty.typ_cmd_libelle FROM commande c,client cl,etape_commande et, type_commande ty where cl.clt_code_pk=c.cmd_clt_fk and c.cmd_etap_cmd_fk = et.etap_cmd_code_pk and c.cmd_typ_cmd_fk = ty.typ_cmd_code_pk' )
SELECT *
FROM #temp_tbl_proc
ORDER BY cmd_nom;
END
The problems are :
the temporary table will be created and added in the database
##query and #query are not recognized as a valid parameter
So how can I fix these problems?
From https://msdn.microsoft.com/en-us/library/ms188427(v=sql.110).aspx
OPENQUERY does not accept variables for its arguments.
So you have to craft a dynamic query, or in your cace, just move the query text into the OPENQUERY
OPENQUERY(SAB, 'Query text comes here')
To pass 'parameters', you can follow the instructions described here: https://support.microsoft.com/en-us/kb/314520
Essentially you have to craft a dynamic query and execute it as a dynamic query text.
You can use the OPENQUERY() a table in queries:
SELECT * FROM OPENQUERY(LinkedServer, 'QueryText') AS R;
Here are some rules to follow:
Add an alias to each returning columns in the QueryText (SQL Server can't handle anonimous columns),
Return only the necessary columns (to decrease the network traffic and the load of the remote and local servers)
You have to add an alias to the OPENQUERY expression in the FROM clause.
So with, a simple example:
DECLARE #localCache TABLE (id INT, col1 VARCHAR(MAX));
INSERT INTO #localCache (id, col1)
SELECT
id, col1
FROM
OPENQUERY(LinkedServer, '
SELECT X.id AS id, Y.col AS col1
FROM X INNER JOIN Y ON X.id = Y.x_id
') src
This could be tricky when you have to pass parameters to the remote query, since you have to create a dynamic query. Dynamic queries are executed in a different context, so the original SP's variables are not available.
DECLARE #myFilter NVARCHAR(32) = 'foo'
DECLARE #dymanicQuery NVARCHAR(MAX) = N'
INSERT INTO #localCache (id, col1)
SELECT
id, col1
FROM
OPENQUERY(LinkedServer, ''
SELECT X.id AS id, Y.col AS col1
FROM X INNER JOIN Y ON X.id = Y.x_id
WHERE Y.col2 = ''''' + #myFilter + '''''
'') src
';
DECLARE #remoteData TABLE (id INT, col1 VARCHAR(MAX));
INSERT INTO #remoteData (id, col1)
EXEC sp_executesql
#stmt = #dymanicQuery
Please note, that this could be dangerous and in this form it is open for sql injecions.
If you can do it, keep the data in sync in a permanent table (using SSIS for example) and use the synchronised data.

Ignore SQL Missing Columns During Execution Time

I am working on a tool (using c# winforms) which generates SQL scripts of data which are independent of identities but yet not violating constraints. While walking through all possibilities I got into below trouble. I need to insert data considering the fact a column (which allows null) may exists or not.
For example, a column as VAL2 exists in dev box, but may or may not exists in prod box.
CREATE TABLE TEMP ( COL1 VARCHAR(50) , VAL1 VARCHAR(50)) -- OPTIONAL/MAY EXISTS VAL2 VARCHAR(50)
IF EXISTS (SELECT TOP(1) COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TEMP' AND COLUMN_NAME = 'VAL2')
BEGIN
INSERT INTO TEMP (COL1,VAL1,VAL2) VALUES ('1','YES','NO')
INSERT INTO TEMP (COL1,VAL1,VAL2) VALUES ('2','NO','NO')
END
ELSE
BEGIN
INSERT INTO TEMP (COL1,VAL1) VALUES ('1','YES')
INSERT INTO TEMP (COL1,VAL1) VALUES ('2','NO')
END
GO
But this method fails miserably if that column is missing even though its should be flowing through else by syntax.
Note: I had for now made a work around but adding that column and dropping it at end if only created through current script. But the problem is the execution is through limited access grant which rules possibility of CREATE/DROP statement.This may be wrong, but that's the way it is for me.
If there is any alternate way preferably which doesn't mandates adding this column , please do guide me.
You'll have to use dynamic sql to accomplish that:
CREATE TABLE TEMP
(
COL1 VARCHAR(50) ,
VAL1 VARCHAR(50)
)
-- OPTIONAL/MAY EXISTS VAL2 VARCHAR(50)
IF EXISTS ( SELECT TOP ( 1 )
COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEMP'
AND COLUMN_NAME = 'VAL2' )
BEGIN
DECLARE #sql NVARCHAR(MAX)
SELECT #sql = 'INSERT INTO TEMP (COL1,VAL1,VAL2) VALUES (''1'',''YES'',''NO'')
INSERT INTO TEMP (COL1,VAL1,VAL2) VALUES (''2'',''NO'',''NO'')'
EXEC sp_executesql #sql
END
ELSE
BEGIN
INSERT INTO TEMP
( COL1, VAL1 )
VALUES ( '1', 'YES' )
INSERT INTO TEMP
( COL1, VAL1 )
VALUES ( '2', 'NO' )
END

SQL server stored procedure return a table

I have a stored procedure that takes in two parameters. I can execute it successfully in Server Management Studio. It shows me the results which are as I expect. However it also returns a Return Value.
It has added this line,
SELECT 'Return Value' = #return_value
I would like the stored procedure to return the table it shows me in the results not the return value as I am calling this stored procedure from MATLAB and all it returns is true or false.
Do I need to specify in my stored procedure what it should return? If so how do I specify a table of 4 columns (varchar(10), float, float, float)?
A procedure can't return a table as such. However you can select from a table in a procedure and direct it into a table (or table variable) like this:
create procedure p_x
as
begin
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t values('a', 1,1,1)
insert #t values('b', 2,2,2)
select * from #t
end
go
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t
exec p_x
select * from #t
I do this frequently using Table Types to ensure more consistency and simplify code. You can't technically return "a table", but you can return a result set and using INSERT INTO .. EXEC ... syntax, you can clearly call a PROC and store the results into a table type. In the following example I'm actually passing a table into a PROC along with another param I need to add logic, then I'm effectively "returning a table" and can then work with that as a table variable.
/****** Check if my table type and/or proc exists and drop them ******/
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'returnTableTypeData')
DROP PROCEDURE returnTableTypeData
GO
IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'myTableType')
DROP TYPE myTableType
GO
/****** Create the type that I'll pass into the proc and return from it ******/
CREATE TYPE [dbo].[myTableType] AS TABLE(
[someInt] [int] NULL,
[somenVarChar] [nvarchar](100) NULL
)
GO
CREATE PROC returnTableTypeData
#someInputInt INT,
#myInputTable myTableType READONLY --Must be readonly because
AS
BEGIN
--Return the subset of data consistent with the type
SELECT
*
FROM
#myInputTable
WHERE
someInt < #someInputInt
END
GO
DECLARE #myInputTableOrig myTableType
DECLARE #myUpdatedTable myTableType
INSERT INTO #myInputTableOrig ( someInt,somenVarChar )
VALUES ( 0, N'Value 0' ), ( 1, N'Value 1' ), ( 2, N'Value 2' )
INSERT INTO #myUpdatedTable EXEC returnTableTypeData #someInputInt=1, #myInputTable=#myInputTableOrig
SELECT * FROM #myUpdatedTable
DROP PROCEDURE returnTableTypeData
GO
DROP TYPE myTableType
GO
Consider creating a function which can return a table and be used in a query.
https://msdn.microsoft.com/en-us/library/ms186755.aspx
The main difference between a function and a procedure is that a function makes no changes to any table. It only returns a value.
In this example I'm creating a query to give me the counts of all the columns in a given table which aren't null or empty.
There are probably many ways to clean this up. But it illustrates a function well.
USE Northwind
CREATE FUNCTION usp_listFields(#schema VARCHAR(50), #table VARCHAR(50))
RETURNS #query TABLE (
FieldName VARCHAR(255)
)
BEGIN
INSERT #query
SELECT
'SELECT ''' + #table+'~'+RTRIM(COLUMN_NAME)+'~''+CONVERT(VARCHAR, COUNT(*)) '+
'FROM '+#schema+'.'+#table+' '+
' WHERE isnull("'+RTRIM(COLUMN_NAME)+'",'''')<>'''' UNION'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #table and TABLE_SCHEMA = #schema
RETURN
END
Then executing the function with
SELECT * FROM usp_listFields('Employees')
produces a number of rows like:
SELECT 'Employees~EmployeeID~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("EmployeeID",'')<>'' UNION
SELECT 'Employees~LastName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("LastName",'')<>'' UNION
SELECT 'Employees~FirstName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("FirstName",'')<>'' UNION
You can use an out parameter instead of the return value if you want both a result set and a return value
CREATE PROCEDURE proc_name
#param int out
AS
BEGIN
SET #param = value
SELECT ... FROM [Table] WHERE Condition
END
GO
I had a similar situation and solved by using a temp table inside the procedure, with the same fields being returned by the original Stored Procedure:
CREATE PROCEDURE mynewstoredprocedure
AS
BEGIN
INSERT INTO temptable (field1, field2)
EXEC mystoredprocedure #param1, #param2
select field1, field2 from temptable
-- (mystoredprocedure returns field1, field2)
END
The Status Value being returned by a Stored Procedure can only be an INT datatype. You cannot return other datatypes in the RETURN statement.
From Lesson 2: Designing Stored Procedures:
Every stored procedure can return an integer value known as the
execution status value or return code.
If you still want a table returned from the SP, you'll either have to work the record set returned from a SELECT within the SP or tie into an OUTPUT variable that passes an XML datatype.
HTH,
John
Though this question is very old but as a new in Software Development I can't stop my self to share what I have learnt :D
Creation of Stored Procedure:
CREATE PROC usp_ValidateUSer
(
#UserName nVARCHAR(50),
#Password nVARCHAR(50)
)
AS
BEGIN
IF EXISTS(SELECT '#' FROM Users WHERE Username=#UserName AND Password=#Password)
BEGIN
SELECT u.UserId, u.Username, r.UserRole
FROM Users u
INNER JOIN UserRoles r
ON u.UserRoleId=r.UserRoleId
END
END
Execution of Stored Procedure:
(If you want to test the execution of Stored Procedure in SQL)
EXEC usp_ValidateUSer #UserName='admin', #Password='admin'
The Output:
create procedure PSaleCForms
as
begin
declare
#b varchar(9),
#c nvarchar(500),
#q nvarchar(max)
declare #T table(FY nvarchar(9),Qtr int,title nvarchar (max),invoicenumber nvarchar(max),invoicedate datetime,sp decimal 18,2),grandtotal decimal(18,2))
declare #data cursor
set #data= Cursor
forward_only static
for
select x.DBTitle,y.CurrentFinancialYear from [Accounts Manager].dbo.DBManager x inner join [Accounts Manager].dbo.Accounts y on y.DBID=x.DBID where x.cfy=1
open #data
fetch next from #data
into #c,#b
while ##FETCH_STATUS=0
begin
set #q=N'Select '''+#b+''' [fy], case cast(month(i.invoicedate)/3.1 as int) when 0 then 4 else cast(month(i.invoicedate)/3.1 as int) end [Qtr], l.title,i.invoicenumber,i.invoicedate,i.sp,i.grandtotal from ['+#c+'].dbo.invoicemain i inner join ['+#c+'].dbo.ledgermain l on l.ledgerid=i.ledgerid where (sp=0 or stocktype=''x'') and invoicetype=''DS'''
insert into #T exec [master].dbo.sp_executesql #q
fetch next from #data
into #c,#b
end
close #data
deallocate #data
select * from #T
return
end
Here's an example of a SP that both returns a table and a return value. I don't know if you need the return the "Return Value" and I have no idea about MATLAB and what it requires.
CREATE PROCEDURE test
AS
BEGIN
SELECT * FROM sys.databases
RETURN 27
END
--Use this to test
DECLARE #returnval int
EXEC #returnval = test
SELECT #returnval