SQL sync count with table group result - c#

I have multiple tables in my SQL Server database.
I have one table [Tatkal_Merge] which has fields like filename,C_srno,Scan,etc. [c_srno is the secondary key]
The second table Collation_Data has details like srno,filename, dispatchcount, totalcount etc. [srno is the primary key]
The totalcount is the total number of records in tatkalmerge table.
There are many other fields in both tables but not relevant to this question.
Whenever the customer scans a barcode in winForm and the update is successful I update [Tatkal_Merge] with scan value 'Y' and increment the Collation_Data dispatch count using stored procedure
update [Tatkal_Merge] set [DScan]=#scan,[DScanBy]=#scanBy,[DScanTime]=getdate() where Dscan='N' and [wl_barcode]=#wl
if(##ROWCOUNT=1)
update Collation_Data set Dqty=Dqty+1 where srno=#C_srno
Issue
Sometimes due to some reason the Dispatch count is not correct by 1 or 2 customers.
Requirement:
1) Please guide why there is a discrepancy in the count. My guess is network issue between first and second command.
2) If am doing it the wrong what is the correct way of doing this?
3) If am doing it the right how to update the Table B in such scenario?
P.S.
Currently, I am updating the collation_Data using correlated subquery periodically,
update Collation_Data c
set Dqty = (select count(*)
from [Tatkal].[dbo].[Tatkal_Merge] m
where m.Dscan = 'Y' and m.collation_code = c.collation_code
);

Few things you can do to isolate and troubleshoot:
Enclose both updates inside a transaction
Trap the ##ROWCOUNT on second update and if that is = 0 it means that the update wasnt succesfull and you could write all the important fields and variables into a logging table that might lead you to the culprit.
The main reason why the second update would fail would be if the ##ROWCOUNT from the first update was <> 1 or if it didnt find any row for that srno. Unlikely that it is a network issue.

if(##ROWCOUNT=1)
this might be an issue if there are more matching rows to the first update of table [Tatkal_Merge]. Instead change it to:
if(##ROWCOUNT > 0)
update Collation_Data set Dqty=Dqty+1 where srno=#C_srno

Related

How to update multi-rows in ORACLE with C# at once(one time IO) or it isn't impossible to happen

How to update data with difference condition and set,
it will be under one time Input and Output
For example as following
Update set column1='1' where id=10;
Update set column1='2' where id=20;
Update set column1='3' where id=30;
......
Update set column1=N where id=N;
Please do me a favor to do this problem
PS: it is / isn't impossible to happen ???
Edit: Simplified the query little more.
And as mentioned in the comment, you should try running it on test data first before running on actual data. Or make sure your session doesn't auto commit the transaction and then run update/delte and after checking, rollback/commit the transaction.
Also as a best practice, run the where clause with select to see how many/what rows are getting returned.
update table
set column1 = (case id
when 10 then '1'
when 20 then '2'
when 30 then '3'
end)
where id in (10,20,30)
Previous:
Try something like below
update table
set column1 = (case when id=10 then '1'
when id=20 then '2'
when id=30 then '3'
end)
where id in (10,20,30)

Error retrieving value of a column from data set

I am filling two tables in DataSet.while retrieving column from 2nd table in dataset i am getting error.Please help!
"There is no row at position 0."
Here is my code.
Stored Procedure
CREATE proc [dbo].[spDispatchDetails]
(
#JobNo int,
#Programme nvarchar(100)
)
as
begin
select ReceivedFrom,ChallanNo,ChallanDate,JobNo,ReceivingDate,LotNo from tblOrders where JobNo=#JobNo and OrderStatus='In Process'
select Quantity from tblProgramme where JobNo=#JobNo and Programme=#Programme
end
I am sharing image of my code.
probably it does not return any rows
you need to check the rows count in ds.Table[1] before you access rows in it.
Make sure that ds.Table[1].Rows.Count > 0
First check if SQL is returning rows, try executing the query manually. While debugging make sure the parameters are being sent correctly (the dropdown selected values)
The error is telling you that there is no rows in the second table. Ideally always check that the row count is greater than zero
On the beginning You should check if Your procedure returns any rows to ds.Tables[1], because this error is very typical to this situation.
Please check this part of Your procedure:
select Quantity from tblProgramme where JobNo=#JobNo and Programme=#Programme
and let us know if You get any rows.
The is no row at position 0
This issue means that there is no row that was returned from the execution of the SQL query for the second table in the dataset. For example, the Quantity value does not exist if the tblProgramme table where the JobNo and Programme match that values passed into the call.
One of the issues with ADO.NET is the amount of effort involved with checking types and row counts, etc.
To solve the issue you should check to ensure that the Table exists and that the Row count is at least 1, and even that the column exists too.
if (ds.Tables.Count == 2 && // Ensure two tables in the dataset
ds.Tables[1].Rows.Count > 0 && // Ensure second table has a row
ds.Tables[1].Rows[0]["Quantity"] != DBNull.Value) // Ensure value for Qty
{
// Then do something with it...
}
As a side note, I would suggest using an ORM as it removes nearly all of the issues that raw ADO.NET boilerplate code introduces.

Order rows with Entity Framework

I'm using EF in order to insert and retrieve info from DB,
there is any way to insert new row but at the specified position,
Like i have 10 rows with IDs ranging from 0 to 9 and new row i'm inserting will be on the position 4?
I'm using ASP.NET MVC 5 and LINQ.
Thank you.
The simple answer is no. Order has no meaning unless it's explicit in a database system. Sure in most cases I can insert into a table and pull from this exact table and get the exact order as it was inserted, but this is undefined...and the only guarantee is to use an ORDER BY clause.
If you are talking about changing an auto number property, this is also not possible, the database does not go back and fill in gaps with id numbers. If numbering is critical and important to you don't set the auto-increment property.
Your ID and order position are different things.
For ID you use an autonumeric and you shouldnt mess with that.
For order you use another column and run a trigger when a new row is insert update all the rows
So when the new row is inserted with order_id = 4 all the rows get update
something like
UPDATE table
set order_id = order_id +1
when order_id >= 4
So, I would do so quickly:
I would plan the database to not auto increment primary key and saving would so that the id is attributed according to the specific location. Obviously put an IF to verify that it is available, and if I would start a review cycle to the cascade of subsequent ID or positioning the value traded in the end.
for example
MyTable table = myDb.MyTable.Find(id); //position
if (table==null)
{ table.id=position; table.Field=value; myDb.SaveChanges() }
else
{
var temp = table.id;
var max = table.count(x=> x.id).value;
table.id=max+1;myDb.SaveChanges();
table.id=id; table.Field=value; myDb.SaveChanges();
}
sorry if translate is no good! ;-)

Primary key violation error in sql server 2008

I have created two threads in C# and I am calling two separate functions in parallel. Both functions read the last ID from XYZ table and insert new record with value ID+1. Here ID column is the primary key. When I execute the both functions I am getting primary key violation error. Both function having the below query:
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name')
Seems like both functions are reading the value at a time and trying to insert with the same value.
How can I solve this problem.. ?
Let the database handle selecting the ID for you. It's obvious from your code above that what you really want is an auto-incrementing integer ID column, which the database can definitely handle doing for you. So set up your table properly and instead of your current insert statement, do this:
insert into XYZ values('Name')
If your database table is already set up I believe you can issue a statement similar to:
alter table your_table modify column you_table_id int(size) auto_increment
Finally, if none of these solutions are adequate for whatever reason (including, as you indicated in the comments section, inability to edit the table schema) then you can do as one of the other users suggested in the comments and create a synchronized method to find the next ID. You would basically just create a static method that returns an int, issue your select id statement in that static method, and use the returned result to insert your next record into the table. Since this method would not guarantee a successful insert (due to external applications ability to also insert into the same table) you would also have to catch Exceptions and retry on failure).
Set ID column to be "Identity" column. Then, you can execute your queries as:
insert into XYZ values('Name')
I think that you can't use ALTER TABLE to change column to be Identity after column is created. Use Managament Studio to set this column to be Identity. If your table has many rows, this can be a long running process, because it will actually copy your data to a new table (will perform table re-creation).
Most likely that option is disabled in your Managament Studio. In order to enable it open Tools->Options->Designers and uncheck option "Prevent saving changes that require table re-creation"...depending on your table size, you will probably have to set timeout, too. Your table will be locked during that time.
A solution for such problems is to have generate the ID using some kind of a sequence.
For example, in SQL Server you can create a sequence using the command below:
CREATE SEQUENCE Test.CountBy1
START WITH 1
INCREMENT BY 1 ;
GO
Then in C#, you can retrieve the next value out of Test and assign it to the ID before inserting it.
It sounds like you want a higher transaction isolation level or more restrictive locking.
I don't use these features too often, so hopefully somebody will suggest an edit if I'm wrong, but you want one of these:
-- specify the strictest isolation level
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name')
or
-- make locks exclusive so other transactions cannot access the same rows
insert into XYZ values((SELECT max(ID)+1 from XYZ WITH (XLOCK)),'Name')

what is a reliable way to return number of records inserted from a stored procedure

I am using INSERT Trigger on that table. Once trigger is executed (it update the table if a condition is meet), that is where the problem is.
int records = sc.ExecuteNonQuery(); // works ok if trigger does not update the record
The above code always ruturns -1 if I leave SET NOCOUNT ON; in the stored procedure itself. If I remove it, I get correct result but if trigger does update the record, then wrong result. I sometime get 10 or a different number. My Trigger looks like this
UPDATE students
SET status = 'Inactive'
FROM Inserted i
INNER JOIN students T2
ON i.sname = T2.sname
AND i.id <> t2.id
That means it can return more than one record (esp in test cases). Can someone tell me what is the cure? I am open to use Functions if that solves the problem or any better approach.
Thanks
Adding Insert SP
CREATE PROCEDURE sp_InsertSudent
-- Add the parameters for the stored procedure here
#student_name varchar(25) = null,
#status varchar(20) = null,
#renew varchar(15) = null,
#edate datetime = null
AS
BEGIN
--SET NOCOUNT ON;
insert into students VALUES(#student_name,#status,#renew,#edate)
END
GO
Note: I am looking for an error because the fields are picked from Excel. if any field is in wrong format or empty, the Insert SP will produce error. I must convey that error to the user.
Adding Actual SP
So the whole problem is in the SP. If I remove it, everything works fine. Here is my actual SP
UPDATE CustomerTbl
SET [Account Status] = 'Inactive',
[End Date] = DateAdd(day,-1,[Supplier End Date]),
[EnrollmentStatus] = 'Waiting'
WHERE OET.[Account No] = (SELECT [Account No] FROM CustomerTbl WHERE id = ##identity)
AND id <> ##identity
The logic is the same as above but stated differently. The ExecuteNonQuery oupts the result of this trigger than than the actual storedprocedure, so what is he cure? Can suppress its output somehow.
I would add Try Catch blocks to the proc and have it return 1 if successful and 0 if not successful.
I also would adjust the trigger to be more efficient by only chaning the status of those where are active and meet the other criteria.
UPDATE students
SET status = 'Inactive'
FROM Inserted i
INNER JOIN students T2
ON i.sname = T2.sname
AND i.id <> t2.id
AND status <> 'inactive'
This could save you from updating 1000 rows when you only really need to update one active row.
My own answer (not complete yet). According to MSDN documentation for ExecuteNonQuery
When a trigger exists on a table being inserted or updated, the return
value includes the number of rows affected by both the insert or
update operation and the number of rows affected by the trigger or
triggers.
This means I need to modify the trigger itself to accommodate the logic, or even by the fact that when trigger is called, that proves that a record was successful. That means if I get anything greater than 0, that should be assumed as success. Although not solid logic but it will work. SET COUNT ON must be commented for this.
maybe I'm not understanding the question, but if your goal is to track the number of rows inserted, then you would maintain a count of how many times you're calling your stored procedure (assuming your sproc inserts one row at a time, of course).
alternately, if you are trying to maintain a count of the total # of records affected (by both inserts and updates), then you could incorporate the logic in the trigger into your sproc. the rows affected by both the insert statement (always 1) and by the update statement (##rowcount after update completes) ... you could then return that value to the caller.
UPDATE:
Sure, return 0 if there is an error. If using SQL2005 (or above), use TRY/CATCH mechanism.
Add an extra column that the stored proc doesnt populate (leaves null)
then when the trigger runs, simply update the Null values to a non-null value and use the RowCount from the Update to determine how many rows were updated.

Categories

Resources