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

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)

Related

How to write a SQL update statement that will fail if it updates more than one row?

A common mistake when writing update statements is to forget the where clause, or to write it incorrectly, so that more rows than expected get updated. Is there a way to specify in the update statement itself that it should only update one row (and to fail if it would update more)?
Correcting an error in the number of rows updated requires thinking ahead - using a transaction, formatting it as a select first to check the number of rows - and then actually catching the error. It would be useful to be able to write in one place the expectation for the number of rows.
Combining a few facts, I found a working solution for Postgres.
A select will fail when comparing using = to a subquery that returns more than one row. (where x = (select ...))
Values can be returned from an update statement, using the returning clause. An update cannot be used as a subquery, but it can be used as a CTE, which can be used in a subquery.
Example:
create table foo (id int not null primary key, x int not null);
insert into foo (id, x) values (1,5), (2,5);
with updated as (update foo set x = 4 where x = 5 returning id)
select id from foo where id = (select id from updated);
The query containing the update fails with ERROR: more than one row returned by a subquery used as an expression, and the updates are not applied. If the update's where clause is adjusted to only match one row, the update succeeds.

##ROWCOUNT Returns Inconsistent Results On Linked Server

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.

OUTPUT Clause in Sql Server (Transact-SQL)

I Know that OUTPUT Clause can be used in INSERT, UPDATE, DELETE, or MERGE statement. The results of an OUTPUT clause in a INSERT, UPDATE, DELETE, or MERGE statements can be stored into a target table.
But, when i run this query
select * from <Tablename> output
I didn't get any error. The query executed as like select * from tablename with out any error and with same no. of rows
So what is the exact use of output clause in select statement. If any then how it can be used?
I searched for the answer but i couldn't find a answer!!
The query in your question is in the same category of errors as the following (that I have also seen on this site)
SELECT *
FROM T1 NOLOCK
SELECT *
FROM T1
LOOP JOIN T2
ON X = Y
The first one just ends up aliasing T1 AS NOLOCK. The correct syntax for the hint would be (NOLOCK) or ideally WITH(NOLOCK).
The second one aliases T1 AS LOOP. To request a nested loops join the syntax would need to be INNER LOOP JOIN
Similarly in your question it just ends up applying the table alias of OUTPUT to your table.
None of OUTPUT, LOOP, NOLOCK are actually reversed keywords in TSQL so it is valid to use them as a table alias without needing to quote them, e.g. in square brackets.
OUTPUT clause return information about the rows affected by a statement. OUTPUT Clause is used along with INSERT, UPDATE, DELETE, or MERGE statements as you mentioned. The reason it is used is because these statements themselves just return the number of rows effected not the rows effected. Thus the usage of OUTPUT with INSERT, UPDATE, DELETE, or MERGE statements helps the user by returning actual rows effected.
SELECT statement itself returns the rows and SELECT doesn't effect any rows. Thus the usage of OUTPUT clause with SELECT is not required or supported. If you want to store the results of a SELECT statement into a target table use SELECT INTO or the standard INSERT along with the SELECT statement.
EDIT
I guess I misunderstood your question. AS #Martin Smith mentioned its is acting an alias in the SELECT statement you mentioned.
IF OBJECT_ID('tempdelete') IS NOT NULL DROP TABLE tempdelete
GO
IF OBJECT_ID('tempdb..#asd') IS NOT NULL DROP TABLE #asd
GO
CREATE TABLE tempdelete (
name NVARCHAR(100)
)
INSERT INTO tempdelete VALUES ('a'),('b'),('c')
--Creating empty temp table with the same columns as tempdelete
SELECT * INTO #asd FROM tempdelete WHERE 1 = 0
DELETE FROM tempdelete
OUTPUT deleted.* INTO #asd
SELECT * FROM #asd
This is how you can put all the deleted records in to a table. The problem with that is that you have to define the table with all the columns matching the table from which you are deleting. This is how i do it.

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.

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