Is there any possible way to execute a non query without having to assign it to a LINQ to SQL class?
Let's say I have this procedure and I want to INSERT only if the Town_Name (UNIQUE CONSTRAINT) is non existent. Otherwise, the UPDATE is executed. This procedure works well and does the job when executed through SQL Server. However, I can't manage to execute it through C# code.
I am trying to avoid using SQL client, as part of my coursework, my little application has to be capable of selecting, inserting / updating and deleting data using LINQ.
The approach I'm taking always results in 0 rows affected.
// Call Procedure.
db.P_SaveClient("000000001M", "Test", "Dummy", null, "+35699999999");
-- Procedure to be executed.
CREATE PROCEDURE Appointment.SaveClient
(
#id NVARCHAR(10),
#firstName NVARCHAR(35),
#lastName NVARCHAR(35),
#tel NVARCHAR(12),
#mob NVARCHAR(12)
)
AS
BEGIN
DECLARE #clientCount TINYINT
SELECT #clientCount = COUNT(Client_ID)
FROM Appointment.Client
WHERE Client_ID = #id
IF #clientCount = 0
BEGIN
INSERT INTO Appointment.Client
VALUES (
#id
, #firstName
, #lastName
, #tel
, #mob
)
END
ELSE
BEGIN
UPDATE Appointment.Client
SET Client_ID = #id
, First_Name = #firstName
, Last_Name = #lastName
, Telephone = #tel
, Mobile = #mob
END
END
Some tutorials I found:
https://www.youtube.com/watch?v=dlXT-vE46sc
https://www.youtube.com/watch?v=-PAMtSwplu8
You're looking for a Merge statement to execute in SQL, which you could call via the stored proc. This will allow you to insert or update depending on whether it was found. It can even return the ID of the record inserted which can save you another query.
Merge Town t
using ( select #Town_Name as 'Town_Name')
src on (src.Town_Name = t.Town_Name )
when NOT MATCHED then
insert (Town_Name) values (src.Town_Name)
output INSERTED.Town_ID
See here for syntax and more examples:
https://msdn.microsoft.com/en-us/library/bb510625.aspx
Related
I'm inserting datatable using stored procedure and created a type table before,
the query is i want to get back all the 'ProdID' that has been inserted in this session.
for the single insertion i can get the scope identity but i want to get all for the recent insertion.
Thanks in advance.
[dbo].[sp_Isert] (#dt_Product Product_Table READONLY, #ProdID int out)
AS
INSERT into tblProduct (Name,Batch,Qty,ExpDate)
SELECT Name, Batch, Qty, ExpDate
FROM #dt_Product;
set #ProdID = Scope_Identity( )
select Scope_Identity( ) ProdID
Do not use scope_identity() - use the output clause instead.
Note that SQL Server does not support table valued parameters as out parameters, meaning the only way to return a record set from a stored procedure is either by using the output clause (not into table) or by executing a select statement.
Also, do not use the sp prefix for stored procedured.
Microsoft is using this prefix for system procedues, so you might get a name collision.
ALTER PROCEDURE [dbo].[stp_Isert] (#dt_Product Product_Table READONLY)
AS
INSERT into tblProduct (Name,Batch,Qty,ExpDate)
OUTPUT Inserted.Id -- This will return a recordset with the inserted ids to the calling application.
SELECT Name, Batch, Qty, ExpDate
FROM #dt_Product;
Update
I've made a sample script for you to check. When I'm running this on my SQL Server instance, I get the expected results:
CREATE TABLE tbl_TestOutputClause (Id int identity(1,1), Col int );
GO
CREATE TYPE udt_TestOutputClauseIntegers AS TABLE (Value int);
GO
CREATE PROCEDURE stp_TestOutputClauseInsert (#Values dbo.udt_TestOutputClauseIntegers READONLY)
AS
INSERT INTO tbl_TestOutputClause(Col)
OUTPUT INSERTED.Id
SELECT Value
FROM #Values;
GO
CREATE PROCEDURE stp_TestOutputClauseGetInsertedValues
AS
DECLARE #Ids AS TABLE (Id int);
DECLARE #Vals dbo.udt_TestOutputClauseIntegers;
INSERT INTO #Vals (Value) VALUES (1), (2), (3);
INSERT INTO #Ids
EXEC stp_TestOutputClauseInsert #Vals;
-- should return three rows with the values 1, 2 and 3.
SELECT *
FROM #Ids;
GO
EXEC stp_TestOutputClauseGetInsertedValues;
-- clean up
DROP TABLE tbl_TestOutputClause;
DROP PROCEDURE stp_TestOutputClauseInsert;
DROP PROCEDURE stp_TestOutputClauseGetInsertedValues
DROP TYPE udt_TestOutputClauseIntegers;
So I am trying to insert data that looks like this:
INSERT INTO RELATIONSHIP_CONFIG (USERID, WORKGROUPID, PRIORITY) VALUES
(#userId, #WorkgroupId10, #SmartFeedPriority10),
(#userId, #WorkgroupId11, #SmartFeedPriority11),
(#userId, #WorkgroupId12, #SmartFeedPriority12),
(#userId, #WorkgroupId13, #SmartFeedPriority13);
Which generally is very simple and linear as all inserts happen one after the other and performs fine (I think).
The issue is that there is a hard limit with the number of SQL Parameters I am allowed to use- 2100.
The upper limit edge case accounts for an insert that is quite a bit above that.
I was thinking about passing the data for WorkgroupId and SmartFeedPriority as a csvs and using a split function to create tables or something like that...
What is the best approach for dealing with data like this?
Maybe creating a stored procedure, passing the #UserId, #WorkgroupId (CSV), and #SmartFeedPriority (CSV) and having linear, one by one inserts done this way, but I am not too sure how the logic for this will look...
Looking at your question it's a bit difficult to suggest a good approach. I'm unable to see how and where the source of the data is.
I see you mentioned a CSV file. You can import data from a CSV file using the below script. Once the data is in a table, you can try one of the below examples.
IF OBJECT_ID('tempdb.dbo.#TempTable', 'U') IS NOT NULL
DROP TABLE #TempTable ;
CREATE TABLE #TempTable
(
[UserID] NVARCHAR(MAX) NULL,
[WorkGroup] NVARCHAR(MAX) NULL,
[SmartFeedPriority] NVARCHAR(MAX) NULL,
)
BULK INSERT #TempTable
FROM ' put your csv file path here '
WITH
(
FIELDTERMINATOR = ',', -- comma delimited
ROWTERMINATOR = '\n',
CODEPAGE = 65001 --'65001'
)
If the data you're trying to insert is from a table, you could try selecting the data into the table you need it to be.
Example :
SELECT [UserID], [WorkgroupID], [SmartFeedPriority]
INTO [dbo].[RELATIONSHIP_CONFIG]
FROM [dbo].[SorceTable]
If you would like to take the procedural route you can try the below. The below sample would work if the source of your data is in a table and you would like to individually insert each record.
Example :
procedure for insert
CREATE PROCEDURE [dbo].[CREATE_RELATIONSHIP_CONFIG](#UserId INT, #WorkgroupId INT, #SmartFeedPriority INT)
AS
BEGIN
INSERT INTO RELATIONSHIP_CONFIG (UserId, WorkgroupId, Priority) VALUES
(#userId, #WorkgroupId, #SmartFeedPriority)
END
You can wrap the above procedure in a while loop.
I've added a example for it below.
declare #UserId int;
declare #WorkgroupId int;
declare #Priority int;
WHILE EXISTS (SELECT [UserID] FROM #TempTable)
BEGIN
SELECT TOP 1 #UserId=[UserID], #WorkgroupId=[WorkGroup] , #Priority=[SmartFeedPriority] FROM #TempTable
EXEC [dbo].[CREATE_RELATIONSHIP_CONFIG] #UserId, #WorkgroupId, #Priority
DELETE TOP (1)FROM #TempTable
END
How can I pass a list of column data into a stored procedure?
My stored procedure is
ALTER PROCEDURE [dbo].[Register]
#Id int,
#Name nvarchar(50)
AS
BEGIN
BEGIN TRY
INSERT INTO dbo.Group (Id, Name)
VALUES(#Id, #Name)
SELECT 0
END TRY
BEGIN CATCH
SELECT -1
END CATCH
END
GO
I want pass like this data for insert into this table
#Id = 1,2,3,4,5
#Name = 'test1,test2,test3,test4,test5'
and result like this
Id Name
1 test1
2 test2
3 test3
4 test4
5 test5
A "list" or "array" in SQL Server is ..... a table. So if you're on SQL Server 2008 or newer (you didn't specify), then use the table-valued parameter feature of SQL Server to pass a table of value to your stored procedure
-- Create a table type to match your input parameters
CREATE TYPE IdNameTable AS TABLE
( ID INT, Name NVARCHAR(50) );
GO
-- change your stored procedure to accept such a table type parameter
ALTER PROCEDURE [dbo].[Register]
#Values IdNameTable READONLY
AS
BEGIN
BEGIN TRY
INSERT INTO dbo.Group (Id, Name)
-- get the values from the table type parameter
SELECT
Id, Name
FROM
#Values
SELECT 0
END TRY
BEGIN CATCH
SELECT -1
END CATCH
END
GO
See the extensive and freely available SQL Server Books Online documentation for more details on the table-valued parameter feature and how to use it
If you want to use this from T-SQL, use this code:
-- declare a variable of that table type
DECLARE #InputTable IdNameTable
-- insert values into that table variable
INSERT INTO #InputTable(ID, Name)
VALUES (1, 'Test 1'), (2, 'Test 2')
-- execute your stored procedure with this table as input parameter
EXECUTE [dbo].[Register] #InputTable
If you want to use this from C# or VB.NET, see Michael Edenfield's link in comments.
I need to insert Tamil language into SQL Server 2005. I have tried using Insert or Update query, it worked fine. While going to stored procedure, I don't know how to pass the parameter.
ALTER PROCEDURE [dbo].[spr_Sam]
#Row_Id int = NULL,
#Description_Ta nvarchar(MAX) = null
AS
BEGIN
update tblTest set
Description_Ta = #Description_Ta
where Row_Id = #Row_Id
END
exec [dbo].[spr_Sam] 2, 'பெண்டிரேம்';
If I execute this it gets inserted as ?????.
exec [dbo].[spr_Sam] 2, N'பெண்டிரேம்';
If I execute this it gets inserted correctly.. but I don't know how to pass that 'N' from my C# Application. I used a text-box to get that Description_Ta parameter.
C# should add the N automatically if you use SqlDbType.NVarChar for SQLParameter
You must be using SqlDbType.VarChar of course
The MSDN doc for SqlDbType states (my bold)
VarChar: A variable-length stream of non-Unicode characters...
...
NVarChar: A variable-length stream of Unicode characters...
Here is the correct update statement:
update tblTest
set Description_Ta = #Description_Ta
where Row_Id = #Row_Id;
You don't need single quotes around a variable.
But, I think the posting is confused. To call the procedure use:
exec [dbo].[spr_Sam] 2, N'பெண்டிரேம்';
To modify it:
ALTER PROCEDURE [dbo].[spr_Sam]
#Row_Id int = NULL,
#Description_Ta nvarchar(MAX) = null
AS
BEGIN
update tblTest
set Description_Ta = #Description_Ta
where Row_Id = #Row_Id;
END;
You shouldn't have arguments when you define the stored procedure.
create procedure InsertQuestionEntry
#round_name varchar(40),
#question varchar(100),
#answer varchar(40),
#option1 varchar(20),
#option2 varchar(30),
#option3 varchar(30)
as
begin
insert into QuestionEntry(Question,Round_Name) values(#question,#round_name);
declare #quesion_id int
exec #quesion_id= select Question_ID from QuestionEntry;
insert into Answer(Question_ID,Answer,Option1,Option2,Option3) values(#quesion_id,#answer,#option1,#option2,#option3);
end
Here I want to retrieve the Question_ID from table QuestionEntry and use that Question_ID to another table Answer
But this didn't work.
So how can I use above way?
please help me
Instead of
insert into QuestionEntry(Question,Round_Name) values(#question,#round_name);
declare #quesion_id int
exec #quesion_id= select Question_ID from QuestionEntry;
use the following:
DECLARE #quesion_id int
INSERT INTO QuestionEntry(Question,Round_Name) values(#question,#round_name)
SET #quesion_id = SCOPE_IDENTITY()
You should not use "exec" there.
What exec does is:
Executes a command string or character
string within a Transact-SQL batch, or
one of the following modules: system
stored procedure, user-defined stored
procedure, scalar-valued user-defined
function, or extended stored
procedure.
You should use "set" or "select" instead of exec.
SET can only assign one variable at
a time, SELECT can make multiple
assignments at once. When assigning
from a query if there is no value
returned then SET will assign
NULL, where SELECT will not make
the assignment at all (so the variable
will not be changed from it's previous
value)
You can find more info about when to use SET or SELECT here: SET vs SELECT when assigning variables
Sample:
set #quesion_id = (select Question_ID from QuestionEntry)
select #quesion_id = (select Question_ID from QuestionEntry)
But that's also wrong way to get identity value from inserted record. If you have N users execute a same procedure at a same time it can happen that you will get wrong value (from last inserted record).
To do this properly you should use ##IDENTITY or even better SCOPE_IDENTITY(). More info: here.
After INSERT you can simply call:
SELECT #quesion_id = ##IDENTITY
--or
SELECT #quesion_id = SCOPE_IDENTITY()
Also, check your Question_ID is configured properly. It should be set to auto increment.
Sample:
Question_ID int IDENTITY(1,1)PRIMARY KEY CLUSTERED
The 1's following the IDENTITY keyword indicate the SEED number (value for first record in table) and increment property (0 or 1).
If your server's version is SQL Server 2005 or higher, you could also try something like this:
create procedure InsertQuestionEntry
#round_name varchar(40),
#question varchar(100),
#answer varchar(40),
#option1 varchar(20),
#option2 varchar(30),
#option3 varchar(30)
as
begin
insert into QuestionEntry(Question,Round_Name)
output inserted.Question_ID, #answer, #option1, #option2, #option3
into Answer (Question_ID, Answer, Option1, Option2, Option3)
values(#question,#round_name);
end