##ROWCOUNT Returns Inconsistent Results On Linked Server - sql

When running select/update statements against a linked server (Oracle) I am getting inconsistent results in ##ROWCOUNT.
SELECT * FROM [LS]..[OWNER].[TABLE] WHERE [KEY] = 'X'
UPDATE [LS]..[OWNER].[TABLE] SET [COL] = 'VALUE' WHERE [KEY] = 'X'
The SELECT returns the 2 rows that are physically in the DB and ##ROWCOUNT=2.
The UPDATE returns ##ROWCOUNT=4.
I would expect the UPDATE to return the same ##ROWCOUNT value (2) as the select, but I must be missing something. Any thoughts?
I had planned on using the ##ROWCOUNT return values to make sure that all outstanding records were in fact updated (without having to do a 3rd SELECT) - but if this is not something I can correct, I'll have to come up with plan B.

Related

Atomic update column in SQL Server

I am using MS SQL Server, and I have a table. I want each SQL Server client to acquire one row and update it, so that the client knows that only he acquired that record, and no one else!
record1 a b c 0
record2 d e f 0
...
One client should acquire and update last value from 0 to 1.
The solution should work at least from SQL Server 2005 and above.
ATOMIC
{
select top 1 * from table where column='0' // get one row where column is '0'
update table set column='1'
}
You could do something like:
update top (1) table with (readpast)
set Column1=1
output inserted.*
where Column1 = 0
Which should do it all in one go. You only need the readpast hint if, having acquired the unique value, the connection keeps a transaction open for a long period of time. If you're just doing the update you can omit it.
You can update a table through a Common Table Expression.
Below I create a CTE that picks just one row and then that is used in the UPDATE.
WITH
singleRow AS
(
select top 1 * from table where column='0'
)
UPDATE
singleRow
SET
column= '1'
;
NOTE: Remember to ensure any preceding commands are terminated with a ;, else the WITH syntax doesn't work.

SQL Error [512] [21000]: Subquery returned more than 1 value

Why does it not work? (SQL Server)
UPDATE
someTable
SET
name='AB'
WHERE
id IN (
SELECT t.id
FROM someTable t
WHERE t.name='ABC'
)
this one doesn't work too
UPDATE
someTable
SET
name='AB'
WHERE
name='ABC'
Because you must have a broken UPDATE trigger on the table.
A common error in triggers is not taking into account that a statement can affect multiple or zero rows and thus that the INSERTED/DELETED tables don't always contain exactly one row.
Look in the trigger for constructs like
SET #ID = (select ID FROM INSERTED)

is "select count(*) from..." more reliable than ##ROWCOUNT?

I have a proc that inserts records to a temp table. In pseudocode it looks like this:
Create temp table
a. Insert rows into temp table based on stringent criteria
b. if no rows were inserted, insert based on less stringent criteria
c. if there are still no rows, try again with even less stringent criteria
select from temp table
There are a lot of IF ##rowcount = 0 checks in the code to see if the table has any rows. The issue is that the proc isn't really doing what it looks like it should be doing and it's inserting the same row twice (steps a and c are being executed). However, if I change it to check this way IF ( (select count(*) from #temp) = 0) the proc works exactly as expected.
Which makes me think that ##rowcount isn't the best solution to this problem. But I'm adding in extra work via the SELECT COUNT(*). Which is the better solution?
##rowcount is the better solution. The work is already done. Selecting count(*) causes the database to do more work.
You need to make sure you are not doing something that will affect the value of ##rowcount before checking the value of ##rowcount. It is usually best to check ##rowcount immediately after performing the insert statement. If necessary assign the value to a variable so you can check it later:
DECLARE #rows int
...
[insert or update a table]
SET #rows = ##rowcount
Storing the row count immediately after any operation that changes row count will allow you to use the value more than once.
##ROWCOUNT will just check "affected rows" from the previous query. This can be a little far reaching as many things can create rows or "affect" rows and some options don't return a value to the client.
Microsoft says:
Statements that make an assignment in a query or use RETURN in a query set the ##ROWCOUNT value to the number of rows affected or read by the query, for example: SELECT #local_variable = c1 FROM t1.
Data manipulation language (DML) statements set the ##ROWCOUNT value to the number of rows affected by the query and return that value to the client. The DML statements may not send any rows to the client.
DECLARE CURSOR and FETCH set the ##ROWCOUNT value to 1.
EXECUTE statements preserve the previous ##ROWCOUNT.
Statements such as USE, SET , DEALLOCATE CURSOR, CLOSE CURSOR, BEGIN TRANSACTION or COMMIT TRANSACTION reset the ROWCOUNT value to 0.
If you are not getting what you expect from ##ROWCOUNT (which probably means your query is more complex than your example) I would definitely be looking at using the SELECT COUNT(*) option, or, if you're worried about the performance hit do something like this:
INSERT INTO temptable
(cols...)
SELECT
COL = #VAL
FROM
sourcetableorquery
LEFT JOIN temptable on [check for existing row]
WHERE
temptable.id is null
This will be faster than the count option if you are looping over a big recordset.
If it's ever being used twice in a row, that could be a problem:
http://beyondrelational.com/blogs/madhivanan/archive/2010/08/09/proper-usage-of-rowcount.aspx

select the rows affected by an update

If I have a table with this fields:
int:id_account
int:session
string:password
Now for a login statement I run this sql UPDATE command:
UPDATE tbl_name
SET session = session + 1
WHERE id_account = 17 AND password = 'apple'
Then I check if a row was affected, and if one indeed was affected I know that the password was correct.
Next what I want to do is retrieve all the info of this affected row so I'll have the rest of the fields info.
I can use a simple SELECT statement but I'm sure I'm missing something here, there must be a neater way you gurus know, and going to tell me about (:
Besides it bothered me since the first login sql statement I ever written.
Is there any performance-wise way to combine a SELECT into an UPDATE if the UPDATE did update a row?
Or am I better leaving it simple with two statements? Atomicity isn't needed, so I might better stay away from table locks for example, no?
You should use the same WHERE statement for SELECT. It will return the modified rows, because your UPDATE did not change any columns used for lookup:
UPDATE tbl_name
SET session = session + 1
WHERE id_account = 17 AND password = 'apple';
SELECT *
FROM tbl_name
WHERE id_account = 17 AND password = 'apple';
An advice: never store passwords as plain text! Use a hash function, like this:
MD5('apple')
There is ROW_COUNT() (do read about details in the docs).
Following up by SQL is ok and simple (which is always good), but it might unnecessary stress the system.
This won't work for statements such as...
Update Table
Set Value = 'Something Else'
Where Value is Null
Select Value From Table
Where Value is Null
You would have changed the value with the update and would be unable to recover the affected records unless you stored them beforehand.
Select * Into #TempTable
From Table
Where Value is Null
Update Table
Set Value = 'Something Else'
Where Value is Null
Select Value, UniqueValue
From #TempTable TT
Join Table T
TT.UniqueValue = T.UniqueValue
If you're lucky, you may be able to join the temp table's records to a unique field within Table to verify the update. This is just one small example of why it is important to enumerate records.
You can get the effected rows by just using ##RowCount..
select top (Select ##RowCount) * from YourTable order by 1 desc

SQL Server 2005 and SELECT and UPDATE locked

I want to perform a update then select the result. I don't want anything to be able to update the row I am updating until after the select has occurred. How would I do this?
My goal is to increment a value of a row and return that incremented value. I have thus far found that I end up with an issue where update (to increment) followed by a select in a situation where two queries happen at near the same time the selects seem to return the same number. So I am guessing that something like update > update > select > select is happening.
I miss labeled this as SQL Server 2005. I am actually working with Server 2000. So the output clause does not work (is not in that version).
BEGIN TRANSACTION
UPDATE Table SET Last=(Last+1) WHERE ID=someid;
SELECT * FROM Table WHERE ID=someid;
COMMIT TRANSACTION
BEGIN TRAN
UPDATE ...
SELECT...
COMMIT
Should do it even at the default transaction isolation level of read committed.
You could also use the OUTPUT clause to get the row directly back after the update. Example of this
UPDATE <YourTable>
SET ...
OUTPUT INSERTED.*
WHERE ...