Joined SELECT blocking UPDATE inside WHILE loop - c#

Gets all fields from Table but only the ones created last, for each different Field
SELECT t1.*
FROM Table AS t1
INNER JOIN (
SELECT Field
, MAX(CreatedOn) AS MaxDate
FROM Table
WHERE ImportedOn IS NULL
AND Status <> 'error'
GROUP BY Field) AS t2
ON t1.Field = t2.Field
AND t1.CreatedOn = t2.MaxDate
I read this data inside a while loop. At the end I try to update the same table - the same record read - and it gives me a timeout. I figure its because the table is blocked for changes.
My question is: How to work around it? Any way to 'fix' the query so it'll accept updates?
Extra info: If I query without JOIN it works perfectly.

Instead of doing an UPDATE row by row after every read; do a JOIN with the table and update. Something like below [A sample; not the exact query]
UPDATE t1
SET column_name = tab.some_column_name
FROM Table t1
JOIN
(
SELECT t1.*
FROM Table AS t1
INNER JOIN (
SELECT Field,
MAX(CreatedOn) AS MaxDate
FROM Table
WHERE ImportedOn IS NULL
AND Status <> 'error'
GROUP BY Field
) AS t2
ON t1.Field = t2.Field
AND t1.CreatedOn = t2.MaxDate
) tab
ON t1.Field = tab.Field

Related

How to select Rows not on HOLDLOCK by another transaction

I am writing a Multi-instance background service, where I would like to process the recent data first, for this I am selecting top 10 records in a batch and marking them from a instance specific id, and then reading them for processing,
This process runs in multiple instances, thus there is a chance of records to be picked by more than one instance and I could generate duplicate results.
To avoid this I would like instance to pick records which are not already put on HOLDLOCK
My current update and select statement looks like this:
ALTER PROC dbo.GetRecordsForInstance #RecordCount INT = 10, #InstanceId varchar(max)
AS
BEGIN
update t with (ROWLOCK) set t.ProcessingStatus =#InstanceId, t.IsProcessing = 1
from SomeTable t
join
(
SELECT TOP (#RecordCount) Col1, Col2
FROM dbo. SomeTable with (ROWLOCK, HOLDLOCK)
WHERE IsProcessing = 0 and IsCompleted = 0
ORDER BY LastModifiedOn
) t1 on t.Id = t1.Id
SELECT * FROM SomeTable with (ROWLOCK) where ProcessingStatus = #InstanceId
END;
You can use the READPAST hint to skip already-locked rows.
You cannot use it with SERIALIZABLE though, you would need to downgrade the isolation level to REPEATABLEREAD. This is not an issue in this case, as the extra guarantee is only regarding new data.
Further improvements:
You can update the t1 derived table directly, there is no need to rejoin. Just select out all columns from that inner table.
You can combine the UPDATE and SELECT using OUTPUT.
To prevent deadlocks in this type of query, you must have an index on your table over the columns which you are querying by (IsProcessing, IsCompleted, LastModifiedOn) preferably with INCLUDE columns also.
CREATE OR ALTER PROC dbo.GetRecordsForInstance
#RecordCount INT = 10,
#InstanceId varchar(max)
AS
UPDATE t
SET
ProcessingStatus = #InstanceId,
IsProcessing = 1
OUTPUT inserted.*
FROM (
SELECT TOP (#RecordCount)
*
FROM dbo.SomeTable t WITH (ROWLOCK, REPEATABLEREAD, READPAST)
WHERE IsProcessing = 0 and IsCompleted = 0
ORDER BY LastModifiedOn
) t;

Sql execption: Maximum stored procedure..level exceeded

This is the first time im using caches. I set my local cache to true in my webconfig.When i try to run my login page is gives the following error
System.Data.SqlClient.SqlException occurred
HResult=0x80131904
Message=Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).
Source=.Net SqlClient Data Provider
StackTrace:
it throws the error on the following code
lock (lastlevelLock)
{
DataSet retval = new DataSet();
if (UseLocalCache)
{
retval =Data.DataRepository.Provider.GetDetailsAll(); // this is where the error comes in
if (retval == null)
retval = new DataSet();
}
else
what am i doing wrong? because the exact same code and db works fine on other machines.I did look at the other similar errors mention on stackflow but nothing helped.
--WITH ENCRYPTION
AS
BEGIN
;WITH cte AS (
SELECT //do selection
FROM Table g WITH(NOLOCK)
)
SELECT //do selection
INTO #cte
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
INNER JOIN table.crumb br WITH(NOLOCK) ON c.ID = br.ID
ORDER BY Lev
SELECT
// select columns
NULL AS ResultExpected
INTO #TempGame
FROM #cte tg
JOIN list.Type gt WITH(NOLOCK) ON tg.TypeID = gt.TypeID
WHERE tg.ID IN (
SELECT ID FROM table2 WITH(NOLOCK)
WHERE ID = tg.ID
)
SELECT
//select columns
INTO #Temp2
FROM tanbe2 m WITH(NOLOCK)
INNER JOIN table g WITH(NOLOCK) ON m.ID = g.ID
//perform all joins
WHERE m.ID IN (SELECT ID FROM #Temp)
GETDATE() < ISNULL(m.ResultDateTime, m.ResultExpected)
SELECT * FROM #Temp
SELECT * FROM #Temp2
ORDER BY ResultExpected
DROP TABLE #cte
DROP TABLE #Temp
DROP TABLE #Temp2
END
GO
After searching and trying different solutions for multiple hours,i finally just restored the db AGAIN and it seemed to work.

SQL query to check the presence of a particular product in multiple tables

I have 7 tables and each table will contain an entry for a particular product.I want to check whether all 7 tables contains entry for a particular ID(eg: 4562). ie, data exists or not.I am using SQL server 2008.Please help me to write a query to check the status.
Try the following command (example for 3 tables T1,T2,T3). It returns 1 if ID = 4562 exists in ALL tables and 0 if at least one table miss this ID.
SELECT
CASE WHEN
(
EXISTS(SELECT ID FROM T1 WHERE ID=4562)
AND EXISTS(SELECT ID FROM T2 WHERE ID=4562)
AND EXISTS(SELECT ID FROM T3 WHERE ID=4562)
)
THEN 1
ELSE 0
END AS [ID_Exists_in_all_tables]
SQLFiddle demo
If you do a basic join rather than left join, the product will only appear if it's in all of the tables.
select * from tab1
join tab2 on tab2.id = tab1.id
join tab3 on tab3.id = tab1.id
join tab4 on tab4.id = tab1.id
join tab5 on tab5.id = tab1.id
Where tab1.id = 1234
etc etc

How can i update another tables after adding record to a table in sql server 2008

I have two same tables created in SQL Server 2008.
What I need is:
Add the newest data inserted in table1 into table2.
Is that possible?
Something like services or triggers or stored procedures?
I think that I have to use triggers, but I don't know how.
I have these two tables:
table1 ( field1,field2,field3 )
table2 ( field1,field2,field3 )
when i insert into table1 i need table2 to be updated as the procedure below:
> IF NotExist(field1=value) in table2 THEN INSERT Into table2 ELSE UPDATE table2
> with new field1 value.
Here is an example:
USE DatabaseName;
GO
IF OBJECT_ID ('Sch.UpdateSecondTable', 'TR') IS NOT NULL
DROP TRIGGER Sch.UpdateSecondTable;
GO
CREATE TRIGGER Sch.UpdateSecondTable
ON FirstTable
AFTER INSERT
AS
INSERT INTO SecondTable
SELECT * FROM Inserted
GO
SQL Fiddle Demo
However, if you want to update the second table form with the inserted values from the first table, try this instead of the INSERT clause:
UPDATE t2
SET t2.name = t1.name
FROM SecondTable t2
INNER JOIN inserted t1 ON t1.id = t2.id
SQL Fiddle Demo
Update: If you want to insert only the values that doesn't exist in the second tabl3e. If these tables are of the same structures, i.e the same column numbers and the same data type. You can use the EXCEPT set operator to do this like so:
UPDATE t2
SET t2.name = t1.name
FROM SecondTable t2
INNER JOIN
(
SELECT * FROM inserted t1
EXCEPT SELECT * FROM SECONDTABLE
) t1 ON t1.id = t2.id
SQL Fiddle Demo
If not use the standard way to do this like so:
UPDATE t2
SET t2.name = t1.name
FROM SecondTable t2
INNER JOIN
(
SELECT * FROM inserted t1
WHERE id NOT IN(SELECT id FROM SECONDTABLE)
) t1 ON t1.id = t2.id
SQL Fiddle Demo
You need to use trigger, its not a big deal, do some research, you will get on the internet.

UpdateCommand for Asp GridView using a join between two tables

I have two tables that I join sims and transactionlog and display in a Asp GridView using a SQLDatasource
Then I have an ASP GridView with the following select and update statements:
SelectCommand="SELECT * FROM sims s INNER JOIN TransactionLog AS tl ON s.id = tl.SimsId"
UpdateCommand="UPDATE SET s.Notes=#Notes FROM sims s INNER JOIN TransactionLog AS tl ON s.id = tl.SimsId WHERE s.id=#id and tl.Id=#Id1"
Right now I only have the Notes column not set to readonly, but would like to add the others in later as soon as I can get the update statement to work for the notes column first.
When I try to update the notes column the error I'm getting is the following:
Incorrect syntax near the keyword 'SET'.]
Mmm, hope my question is stated clearly enough.
This is how you write and SQL UPDATE statement with the FROM clause.
drop table t2
drop table t1
go
create table t1 (
Id int not null identity(1,1) primary key,
Name varchar(50) null
)
create table t2 (
t1Id int not null foreign key references t1(id),
Name varchar(50) null
)
insert into t1(name) values('T1Test1')
insert into t1(name) values('T1Test2')
insert into t2(t1Id, name) values(1, 'T2Test1')
insert into t2(t1Id, name) values(2, 'T2Test2')
-- Have a look at the data
select * from t1 inner join t2 on t1.Id = t2.t1Id
update t2
set t2.Name = 'T2Test1_changed'
from t2 inner join t1 on t2.t1Id = t1.Id
where t1.Id = 1
-- See the changes
select * from t1 inner join t2 on t1.Id = t2.t1Id
This means that your statement should look like this:
UPDATE sims
SET s.Notes = #Notes
FROM sims s INNER JOIN TransactionLog tl ON s.id = tl.SimsId
WHERE s.id = #id and tl.Id = #Id1
I do however doubt the WHERE clause. Maybe there's no need to use both IDs there, but only you know that.
Try you queries in SQL Management Studio before applying them in you application for a better debugging experience.
Here is the MSDN docs on the UPDATE statement: http://msdn.microsoft.com/en-us/library/ms177523.aspx

Categories