Does someone know how can I return the ##Identity when using T-Sql?
Something like this:
set #Sql = "insert into table....values()..."
exec #sql
return ##Identity
It looks like one of your implicit requirements is the execution of dynamic SQL. While I'd advise against this, you can accomplish what you're looking for with this:
set #Sql = 'insert into table....values()...; select SCOPE_IDENTITY()'
exec(#Sql)
Like this:
INSERT INTO Table(...)
OUTPUT INSERTED.IdColumn
VALUES(...)
INSERT INTO TableName (Field1, Field2, Field3) VALUES (1, 2, 3);
SELECT SCOPE_IDENTITY();
This is a multi-statement batch, so I'm not sure that every client library will return values the same way; in classic ADO, for example, it's possible that you might need to advance to the next recordset before you can read the value. But if you're using ADO.NET, I know that you can just use ExecuteScalar on the whole string above, and it will return your SCOPE_IDENTITY value just fine.
Caution: ADO.NET will return the value as a decimal, not an int like you might expect. This is because SCOPE_IDENTITY, for whatever reason, is typed as numeric(38,0). So you either need to cast the ExecuteScalar result to decimal before you cast it to int, or you need to SELECT CAST(SCOPE_IDENTITY() AS INT) (assuming your IDENTITY field is an INT, and not some larger numeric type).
Append ";select ##identity" to your insert statement:
insert into tab (x,y,z) values (a,b,c); select ##identity
The returned value is the ID (use ExecuteScalar)
You can use this
Insert into Table(Col2, Col3)
output inserted.Id
values ('xyz', 'abc')
Where Id is your Identity field
Related
I have a SP with an Output parameter that looks like:
ALTER PROCEDURE [dbo].[SP_Name] #VarName decimal(18,2) OUTPUT as ...
I call that procedure from vb.net to get the value for calculations. My problem is: I have 8 SP's with the following structure:
CREATE PROCEDURE [dbo].[SP_Name] #VarName decimal(18,2) OUTPUT as ...
CREATE TABLE #TempTable
Begin
Select ...
End
SET #VarName = Result
But the TempTable is always the same. No I am looking for a way to get all 8 values with only one stored procedure. My idea:
CREATE PROCEDURE [dbo].[SP_Name] #VarName decimal(18,2) OUTPUT as ...
CREATE TABLE #TempTable
---Get first value
Begin
Select ...
End
SET #VarName1 = Result
---Get second value
Begin
Select ...
End
SET #VarName2 = Result
...
How do i have to rewrite the line: ALTER PROCEDURE [dbo].[SP_Name] #VarName decimal(18,2) OUTPUT ir can I even work with an array?
You can use a single stored procedure with all your queries in it. Following will return a single row result set with eight fields and you can grab them from your code using the specific filed name or index.
CREATE PROCEDURE [dbo].[SP_Name]
#VarName decimal(18,2)
AS
BEGIN
DECLARE #VarName1 Datatype, #VarName2 Datatype, ...#VarName8 Datatype
SELECT #VarName1 = yourCol
FROM --First query
SELECT #VarName2 = yourCol
FROM --Second query
...
SELECT #VarName8 = yourCol
FROM --Eighth query
--Finally Select all the variables
SELECT #VarName1 Col1, #VarName2 Col2, ...,#VarName8 Col8
END
OR if you are looking to return results of your all 8 queries, that is also possible. Simply do your select queries in a single stored procedure and grab the DATASET from your code and you can access individual table using zero based Index (ex DataTable1 = YourDataSet.Tables[0])
I use SQL Server 2012, and T-SQL as query language.
I need help updating/inserting multiple columns in [cross_function_user] using one ID value passed as a parameter (#userGroupID) and lots of function id's. They are List in C#, and passed to the sproc as Table Valued Parameter - with just one column of int, named Item.
ALTER PROCEDURE [whatever]
#userGroupID INT,
#listID AS IntList READONLY
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO [dbo].[cross_function_user] USING #listID
ON [dbo].[cross_function_user].id_group_user = #userGroupID
WHEN MATCHED THEN
UPDATE SET [cross_function_user].id_group_user = #userGroupID,
[cross_function_user].id_function = (SELECT Item FROM #listID)
WHEN NOT MATCHED THEN
INSERT (id_group_user, id_function)
VALUES (#userGroupID, (SELECT Item FROM #listID) );
END
First, it errors 'subquery returned more than one result' of course, but I lack skill to rewrite this, and I'm not really sure if my upsert is written right way. Any help would be highly appreciated.
Try this:
You need to replace YourColumn with the name of the column in your TVP.
ALTER PROCEDURE [whatever]
#userGroupID INT,
#listID AS IntList READONLY
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO [dbo].[cross_function_user] USING #listID
ON [dbo].[cross_function_user].id_group_user = #userGroupID
WHEN MATCHED THEN
UPDATE SET [cross_function_user].id_function = S.YourColumn
WHEN NOT MATCHED THEN
INSERT (id_group_user, id_function)
VALUES (#userGroupID, S.YourColumn);
END
Perhaps a stupid question!
If I call a stored proc from an After Insert trigger (T-SQL) - then how do I get the values of the "just inserted" data?
e.g.
CREATE TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
EXEC createAuditSproc 'I NEED VALUES HERE!'
I don't have any identity columns to worry about - I just want to use some of the "just inserted" values to pass into my sproc.
Edit: For clarification - I need this to call a sproc and not do a direct insert to the table, since the sproc does more than one thing. I'm working with some legacy tables I can't currently amend to do things 'properly' (time/resource/legacy code), so I have to work with what I have :(
You get to the newly 'changed' data by using the INSERTED and DELETED pseudo-tables:
CREATE TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
INSERT INTO myTableAudit(ID, Name)
SELECT i.ID, i.Name
FROM inserted i;
END
Given the example tables
create table myTable
(
ID INT identity(1,1),
Name varchar(10)
)
GO
create table myTableAudit
(
ID INT,
Name varchar(10),
TimeChanged datetime default CURRENT_TIMESTAMP
)
GO
Edit : Apologies, I didn't address the bit about calling a Stored Proc. As per marc_s's comment, note that inserted / deleted can contain multiple rows, which complicates matters with a SPROC. Personally, I would leave the trigger inserting directly into the audit table without the encapsulation of a SPROC. However, if you have SQL 2008, you can use table valued parameters, like so:
CREATE TYPE MyTableType AS TABLE
(
ID INT,
Name varchar(10)
);
GO
CREATE PROC dbo.MyAuditProc #MyTableTypeTVP MyTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO myTableAudit(ID, Name)
SELECT mtt.ID, mtt.Name
FROM #MyTableTypeTVP mtt;
END
GO
And then your trigger would be altered as like so:
ALTER TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MyTableTypeTVP AS MyTableType;
INSERT INTO #MyTableTypeTVP(ID, Name)
SELECT i.ID, i.Name
FROM inserted i;
EXEC dbo.MyAuditProc #MyTableTypeTVP;
END
you can then test that this works for both a single and multiple inserts
insert into dbo.MyTable values ('single');
insert into dbo.MyTable
select 'double'
union
select 'insert';
However, if you are using SQL 2005 or lower, you would probably need to use a cursor to loop through inserted passing rows to your SPROC, something too horrible to contemplate.
As a side note, if you have SQL 2008, you might look at Change Data Capture
Edit #2 : Since you need to call the proc, and if you are certain that you only insert one row ...
ALTER TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SomeInt INT;
DECLARE #SomeName VARCHAR(10);
SELECT TOP 1 #SomeInt = i.ID, #SomeName = i.Name
FROM INSERTED i;
EXEC dbo.MyAuditProc #SomeInt, #SomeName;
END;
Suppose I have following SP to run a dynamic sql
ALTER PROCEDURE [dbo].[MySP]
AS
BEGIN
declare #sql varchar(4000)
select #sql = 'select cnt = count(*) from Mytable ..... ';
exec (#sql)
END
then in edmx, I add the sp and import function for this sp. the return type is scalars int32.
then I want to use this function in code like:
int? result = context.MySP();
I got error said "cannot implicitly convert type System.Data.Objects.ObjectResults to int?"
If use
var result = context.MySP();
then Single() cann't be applied to context.MySP().
How to get the result for this case?
You may have already resolved this, but ...
I had done the same thing; my procedure was returning an integer so I selected Scalars and Int32, and it was returning System.Data.Objects.ObjectResult
Of course, the problem is the window states "Returns a Collection Of" (emphasis mine).
Durr.
Select None instead of Scalars and the appropriate result (int) will be returned.
Try changing your result datatype to System.Nullable<int>. See this post.
I would like to do the following. Basically have a stored procedure call another stored procedure that returns a table. How is this done?
ALTER PROC [GETSomeStuff]
AS
BEGIN
#table = exec CB_GetLedgerView #accountId, #fromDate, #toDate, #pageSize, #pageNumber, #filter, #status, #sortExpression, #sortOrder, #virtualCount OUTPUT
Select * from #table
--Do some other stuff here
END
The target of a stored procedure has to be a temp or actual table so you can
Insert into #table exec CB_GetLedgerView #accountId, #fromDate,
#toDate, #pageSize, #pageNumber,
#filter, #status, #sortExpression,
#sortOrder, #virtualCount OUTPUT
If the output result set of the stored procedure does not match the ordinal positions and count of the rows in the target table, specify a column list.
The temporary-table approach, at least as expressed above, didn't work for me. You can use a variable, just as easily.
DECLARE #return_value INT
DECLARE #tblOutputTable TABLE(Col1 BIT NOT NULL, Col2 INT NOT NULL)
INSERT INTO #tblOutputTable EXEC #return_value = [dbo].[SomeSp] #Param1 = 15, #Param2 = 2
Maybe your example isn't really representative, but the first question I'd have have is, do you really need to make this two procedures, at the cost of greater complexity? Decomposition like this is somewhat of an antipattern with SQL. (Although some will disagree, but I've seen this discussed with majority agreement here on SO.)