Duplicate Entry Insertion while insertion of DataTable in Stored Procedure - c#

I'm inserting DataTable in Database using StoredProcedure but the issue is, its inserting twice the actual number of entries of DataTable to be inserted, the procedure is below, kindly guide me, if I'm using wrong approach, why its duplicating the rows? The return which is required is working fine.
Thanks In Advance
ALTER PROCEDURE [dbo].[proc_InsertStore_Recvry]
(#dt_Recovery Recovery_Store READONLY)
AS
Declare #RecoveryIDs as Table (IDs int, ClientIds int)
declare #StoreID int
declare #ClientID int
declare #Arrears decimal(18, 2)
declare #NetDues decimal(18, 2)
declare #Received decimal(18, 2)
Declare #RecoveryRecID int
begin
select * into #tempTable from #dt_Recovery
declare #Count int
set #Count= (select COUNT(*) from #tempTable)
while(#Count > 0)
begin
set #Count = #Count-1
set #ClientID = (Select top 1 ClientID from #tempTable)
set #StoredID = (Select top 1 StoredID from #tempTable where ClientID=#ClientID)
set #Arrears = (Select top 1 Arrears from #tempTable where ClientID=#ClientID)
set #NetDues = (Select top 1 NDues from #tempTable where ClientID=#ClientID)
set #Received = (Select top 1 Received from #tempTable where ClientID=#ClientID)
Insert into tblRecovery (StoreID, ClientID, Arrears, NetDues, Received)
values (#StoreID,#ClientID,#Arrears,#NetDues,#Received)
select #RecoveryID = Scope_Identity()
insert into #RecoveryIDs (IDs,ClientIds) values (#RecoveryID, #ClientID )
delete from #tempTable where ClientID=#ClientID
end
Select * from #RecoveryIDs

it looks like you are using SQL Server. If yes then why are you using a while-loop to insert values into a table and return the inserted Ids?
The same can be accomplished in a far better way via the OUTPUT clause:
OUTPUT documentation
Example:
INSERT INTO tblRecovery(StoreID, ClientID, Arrears, NetDues, Received) OUTPUT INSERTED.ID, INSERTED.CLientId INTO #RecoveryIDs(IDs, ClientIds) SELECT StoredID, ClientID, Arrears, NDues, Received FROM #tempTable
Aside from that there seems to be no issue with your SQL code. So could you post the .NET code as well?

Related

How to create multiple tables dynamiclly in view by using following data in list

My requirement is to create multiple tables dynamic
here is part numbers .table number
1. table number 1 has 2 records and table number 2 has also 2 records.
firstly create table no. 1 and fill its records
after that create new second table no. 2 and its records and soo on according to table number
in some case i have only part no. but in this we create another something html in which we display those data which does not have table no.
Declare table variable to store id and tableNo.
declare #TempTable table(id int identity,TableNo int)
Insert into this table of all distinct TableNo column data..
INSERT INTO #TempTable
SELECT DISTINCT TabloNo
FROM TableName
Declare following variable and set its value like...
declare #counter int, #totalTable int, #NoOfTable int, #StrquryInser nvarchar(max)
select #totalTable = count(id) from #TempTable
set #counter = 1
set #StrquryInser = ''
In while block select table data according to tableNo and insert it into #temp1, #temp2...dynamically using this code...
begin
select #NoOfTable = TableNo
from #TempTable
where id = #counter
set #StrquryInser = #StrquryInser + ' select * into #temp' +cast(#counter as varchar(10)) + ' from TableName where isnull([TabloNo],0)='+cast(isnull(#NoOfTable,0) as nvarchar(10))
set #StrquryInser=#StrquryInser + ' select * from #temp' +cast(#counter as varchar(10))
set #counter=#counter+1
end
execute the string Query #StrquryInser like...
exec(#StrquryInser)
In above query you can store your table data in multiple temp variables like temp1, #temp2 etc..
Apart form these #temp table you can also store your data in permanent table using above logic..

SQL While loop or c# linq foreach?

I have a credit card payment process stored procedure written in SQL. This is using SQL while to loop through half million payment records. This is horribly slow, because i have to loop through another set of data for each of these payment records and update bunch of tables accordingly. That means while loop inside while loop in sql.
I have to re-write this in c# to improve the performance. We are using LINQ & Entity framework. Can anybody please suggest me if this is going to help or not?
Thanks
Updating my question with modified stored procedure. I have replaced the references to my tables and removed some part of the code. But let me know if this is not clear.
CREATE PROCEDURE [dbo].[USP_ProcessPayments]
(
#UserKey int
)
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #TempUserPayments
(
-- with Columns declared
)
INSERT INTO #TempUserPayments
SELECT DISTINCT up.*, ROW_NUMBER() OVER(ORDER BY up.UserKey DESC, up.DateReceived) AS RN --generate row number
FROM UserPayment up
where up.UserKey = #UserKey
CREATE INDEX UP_1 on #TempUserPayments (RN);
DECLARE #LOOPCOUNTER INT, #ROWCOUNTER INT, #REQUESTEDAMOUNT MONEY, #UPDATEDREQUESTEDAMOUNT MONEY, #AMOUNT MONEY,
#AMOUNTNOTAPPLIED MONEY, #APPLIEDAMOUNT MONEY, #SYSTEMKEY INT, #LOOPCOUNTER_PR INT, #ROWCOUNTER_PR INT, #IS_UPDATE BIT
SELECT #ROWCOUNTER = COUNT(*) from #TempUserPayments;
SET #LOOPCOUNTER = 1
WHILE (#LOOPCOUNTER <= #ROWCOUNTER)
BEGIN
SELECT *,
ROW_NUMBER() OVER (ORDER BY mp.Month DESC, mp.PayPriority) AS RN_PR
INTO #TempPR
FROM Requests pr
INNER JOIN Premium mp ON mp.PremiumKey = pr.PremiumKey
--Joing couple of other tables here
ORDER BY mp.[Month] DESC, mp.PayPriority
CREATE INDEX PR_1 on #TempPR (RN_PR);
SELECT #SYSTEMKEY = SystemKey FROM #TempUserPayments WHERE RN = #LOOPCOUNTER;
SELECT #ROWCOUNTER_PR = COUNT(*) from #TempPR;
SET #LOOPCOUNTER_PR = 1
WHILE (#LOOPCOUNTER_PR <= #ROWCOUNTER_PR)
BEGIN
SET #IS_UPDATE = 0;
IF(#APPLIEDAMOUNT IS NULL OR (#REQUESTEDAMOUNT <> #APPLIEDAMOUNT AND #APPLIEDAMOUNT < #REQUESTEDAMOUNT))
BEGIN
IF(#SYSTEMKEY = 1 OR #SYSTEMKEY = 3)
BEGIN
--Check all the conditions here
SET #IS_UPDATE = 1;
END
IF(#IS_UPDATE = 1)
BEGIN
--Update bunch of requets tables ---
INSERT INTO userpaid
(
--Column names --
)
VALUES
(
--Values --
)
END
END
-- END
SET #LOOPCOUNTER_PR = #LOOPCOUNTER_PR + 1;
END
SET #LOOPCOUNTER = #LOOPCOUNTER + 1;
DROP TABLE #TempPR;
END
DROP TABLE #TempUserPayments;
END

Calling stored procedure from another stored procedure with parameters

I have a stored procedure with takes 2 parameters (StudentID and CurrentSmester) as input and return me table with fields :
Course Code
Update Type
Update Id
This stored procedure is created by another team in my office. I can not modify it but at the same point I want to use it in my Webservice (which I am building for android) to make sure data remains consistent.
My requirement is to get :
Course Code
Update Type
Update Id
Course Title
Can I create another store procedure which will call that store procedure with parameters as I mentioned, make a join with course table to get course title too.
Is this possible ? If yes can you please guide me through its implementation.
Thanking You and Happy New Year !!
Create a new stored procedure , insert the results coming back from your existing stored procedure into a temp table, join your Course table with that temp table and you are good to go ,
something like this.....
CREATE PROCEDURE usp_NewProc
#StudentID INT ,
#CurrentSmester INT
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
CourseCode [DataType],
UpdateType [DataType],
Update Id [DataType]
)
INSERT INTO #temp
EXEC existsting_proc #StudentID , #CurrentSmester
SELECT t.* , C.CourseTitle
FROM #temp t INNER JOIN CourseTable C on <join Condition>
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL
DROP TABLE #temp
END
You can insert the results from the STORED PROCEDURE into a temp table (table variable or temp table) and them select from that table and join onto the Courses table to retrieve the title.
SQL Fiddle DEMO
Example code
CREATE TABLE Courses(
CourseCode VARCHAR(50),
CourseName VARCHAR(250)
);
INSERT INTO Courses VALUES ('A','AA'), ('B','BB');
CREATE PROCEDURE OtherTeamsSP(
#StudentID INT,
#CurrentSmester INT
)
AS
SELECT 'A' CourseCode,
'FOO' UpdateType,
1 UpdateId;
CREATE PROCEDURE MyProcedure(
#StudentID INT,
#CurrentSmester INT
)
AS
CREATE TABLE #SPOutput(
CourseCode VARCHAR(50),
UpdateType VARCHAR(50),
UpdateId INT
)
INSERT INTO #SPOutput
EXEC OtherTeamsSP #StudentID, #CurrentSmester
SELECT *
FROM #SPOutput s INNER JOIN
Courses c ON s.CourseCode = c.CourseCode
DROP TABLE #SPOutput
Calling the new SP
EXEC MyProcedure 1,2
-- First Stored Procedure
CREATE PROCEDURE FirstSP
#MyFirstParam INT
AS
DECLARE #MyFirstParamValue INT
SELECT #MyFirstParamValue = #MyFirstParam * #MyFirstParam
RETURN (#MyFirstParamValue)
GO
-- Second Stored Procedure
CREATE PROCEDURE SecondSP
#SecondParam INT
AS
DECLARE #SecondParamValue INT
SELECT #SecondParamValue = #SecondParam * #SecondParam
RETURN (#SecondParamValue)
GO
-- Pass One Stored Procedure's Result as Another Stored Procedure's Parameter
DECLARE #FirstValue INT, #SeondValue INT
-- First SP
EXEC #FirstValue = FirstSP 5
-- Second SP
EXEC #SeondValue = SecondSP #FirstValue
SELECT #SeondValue SecondSP
GO
-- Clean up
DROP PROCEDURE FirstSP
DROP PROCEDURE SecondSP
GO

using stored procedure in entity framework

I'm trying to add the following sproc to Entity Framework. After adding this via "Update from Model" the Model Browser shows this sproc in the "Function Imports" and "Stored Procedures/Functions" of the model. Using the "Edit" from Function Imports dialog I can not "Get Column Information" and unsuccessfully determine a Return type for the collection.
The output from the sproc is a temporary table but I do define the columns being returned. Is this sproc the problem? Am I missing a step in setting up the EF?
ALTER PROCEDURE [dbo].[addrApproxSP]
-- Add the parameters for the stored procedure here
#frontage bigint = 0,
#housedir varchar(1) = 0,
#streetnum bigint = 0,
#streetdir varchar(1) = 0,
#distance bigint = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Set Variables
DECLARE #lowfront bigint,
#highfront bigint,
#lowstreet bigint,
#highstreet bigint,
#currname varchar(25),
#streetcur varchar(25),
#whereclause varchar(40),
#fixstreet varchar(25),
#pos int,
#piece varchar(500)
--Set variables to proper values in range
Set #lowfront = #frontage - #distance
set #highfront = #frontage + #distance
set #lowstreet = #streetnum - #distance
set #highstreet = #streetnum + #distance
-- Process for Street Names that are Numeric Values
-- Create Temp Table
CREATE TABLE #StreetNames
(streetname varchar(25))
-- SELECT StreetName and put in Temp table
INSERT #Streetnames(streetname)
select distinct streetname
from ADDR_STREETCOORD
where begincoord between #lowstreet and #highstreet
and STREETDIR = #streetdir
and lowhouse > #lowfront and HIGHHOUSE < #highfront
and HOUSEDIR = #housedir
union
select distinct streetname
from ADDR_STREETCOORD
where lowhouse > #lowstreet and HIGHHOUSE < #highstreet
and HOUSEDIR = #housedir
and begincoord between #lowfront and #highfront
and STREETDIR = #streetdir
-- Check each Streetname and those that are a coordinate (ex: "1000 S") change to "1000"
CREATE TABLE #FixStreets(streetname varchar(25))
DECLARE curStreet CURSOR FOR SELECT streetname FROM #StreetNames
OPEN curStreet
FETCH NEXT FROM curStreet INTO #fixstreet
WHILE ##FETCH_STATUS = 0
BEGIN
--insert code here
INSERT #FixStreets(streetname)
--Call Function to: parse the street name
--if the first part isnumeric then insert that
--if not numeric then keep as is
select [dbo].fnParseCoordinate(#fixstreet)
FETCH NEXT FROM curStreet INTO #fixstreet
END
CLOSE curStreet
DEALLOCATE curStreet
--select * from #FixStreets
--create a temp table to store the results of each street name in a single table
-- in order to return the results as a single table
--For Each street name search its frontage range values
--loop through each streetname to get the parcels matching those streets
CREATE TABLE #AllResults(Parcel varchar(14),Prop_locat varchar(50))
DECLARE curName CURSOR FOR SELECT streetname FROM #FixStreets
OPEN curName
FETCH NEXT FROM curName INTO #streetcur
WHILE ##FETCH_STATUS = 0
BEGIN
--insert code here
INSERT #AllResults(Parcel, Prop_locat)
select parcel_id,prop_locat
from ADDR_ParcelsWWW
where StreetName = #streetcur
and predir = #housedir
and housefrom between #lowfront and #highfront
union
select parcel_id,LOCATOR_ADDRESS
from ADDR_MASTERADDRESS
where StreetName = #streetcur
and predir = #housedir
and housefrom between #lowfront and #highfront
FETCH NEXT FROM curName INTO #streetcur
END
CLOSE curName
DEALLOCATE curName
--Select the results of all the tables
select Parcel, prop_locat from #AllResults
END
When EF polls your SP, it does this first: SET FMTONLY ON
This can screw things up if you use temp tables in your SP, which it looks like you're doing.
Try explicitly setting this at the beginning of your SP: SET FMTONLY OFF
That should allow EF to detect your columns.

SQL Server (2008) Pass ArrayList or String to SP for IN()

I was wondering how I can pass either an ArrayList, List<int> or StringBuilder comma delimited list to a stored procedure such that I find a list of IDs using IN():
#myList varchar(50)
SELECT *
FROM tbl
WHERE Id IN (#myList)
In C# I am currently building the list as a string which is comma delimeted; however when using nvarchar(50) for example, as the type for the param in the stored procedure - I get an error as it can't convert '1,2,3' to int which it expects between the IN().
Any ideas? Much appreciated.
Pete
You could use a User Defined function such as
CREATE function [dbo].[csl_to_table] ( #list nvarchar(MAX) )
RETURNS #list_table TABLE ([id] INT)
AS
BEGIN
DECLARE #index INT,
#start_index INT,
#id INT
SELECT #index = 1
SELECT #start_index = 1
WHILE #index <= DATALENGTH(#list)
BEGIN
IF SUBSTRING(#list,#index,1) = ','
BEGIN
SELECT #id = CAST(SUBSTRING(#list, #start_index, #index - #start_index ) AS INT)
INSERT #list_table ([id]) VALUES (#id)
SELECT #start_index = #index + 1
END
SELECT #index = #index + 1
END
SELECT #id = CAST(SUBSTRING(#list, #start_index, #index - #start_index ) AS INT)
INSERT #list_table ([id]) VALUES (#id)
RETURN
END
Which accepts an nvarchar comma separated list of ids and returns a table of those ids as ints. You can then join on the returned table in your stored procedure like so -
DECLARE #passed_in_ids TABLE (id INT)
INSERT INTO #passed_in_ids (id)
SELECT
id
FROM
[dbo].[csl_to_table] (#your_passed_in_csl)
SELECT *
FROM
myTable
INNER JOIN
#passed_in_ids ids
ON
myTable.id = ids.id
In SQL 2008 there are table-valued-parameters, that make a friendly alternative to parsing CSV; see here for an example.
Otherwise, another option is xml - the xml data type in SQL Server allows you to read this pretty easily (although it takes more transfer bytes).

Categories

Resources