MSSQL update multiple rows based on select statement - sql-server

I am trying to update multiple rows in one table, based on a select statement on another table.
This is my query:
UPDATE dbo.[user_message_content]
SET [status] = 1
WHERE [message_id] = (SELECT [message_id] FROM dbo.[user_message] WHERE [receiver_id] = #userID)
AND [status] = 0
This select statement may return multiple rows, which leads me to this error:
Msg 512, Level 16, State 1, Procedure usp_profileUserMessageMarkAsRead, Line 11
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
What is the correct way to achieve what I need?
Thanks very much

If you want to update all those records, change the = to IN:
UPDATE dbo.[user_message_content]
SET [status] = 1
WHERE [message_id] IN
( SELECT [message_id] FROM dbo.[user_message] WHERE [receiver_id] = #userID )
AND [status] = 0

You can also use UPDATE with FROM clause http://msdn.microsoft.com/en-us/library/aa260662(SQL.80).aspx.
USE tempdb;
GO
create table #user_message_content([status] int, message_id int)
create table #user_message (message_id int,receiver_id int)
declare #UserID int
UPDATE mc
SET mc.[status] = 1
FROM #user_message_content mc join #user_message m on mc.message_id = m.message_id
WHERE m.receiver_id = #userID
AND mc.[status]=0;
drop table #user_message_content
drop table #user_message

I think you need to use a join to do this
USE dbo; // Sets the current database to dbo, I did this for readability
UPDATE user_message_content join user_message on user_message_content.message_id = user_message.message_id
SET user_message_content.status = 1
WHERE user_message.receiver_id = #userID;

Related

Stored procedure error: Msg 512, Level 16, State 1, Procedure sp_ActFTC, Line 64 Subquery returned more than 1 value

After executing a stored procedure, I get the following error:
Msg 512, Level 16, State 1, Procedure sp_ActFTC, Line 64
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I have two tables in the database, FTC_Alt and FichaTecnicaComp, and I need to update the FichaTecnicaComp table on a given date.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_ActFTC]
AS
DECLARE #Codigo NVARCHAR(20),
#DataAlteracao DATE,
#Categoria NVARCHAR(20),
#catord INT,
#SubCategoria NVARCHAR(255),
#subcatord INT,
#Ordem INT,
#CodigoComp NVARCHAR(10),
#DesignacaoComp NVARCHAR(50),
#QuantidadeComp NVARCHAR(25),
#UnidadeComp NVARCHAR(5),
#intRowCount INT,
#upAction NVARCHAR(255);
SELECT #Codigo = ft_alt.codigo
FROM ft_alt;
SELECT #DataAlteracao = ft_alt.dataalteracao
FROM ft_alt;
SELECT Categoria = ftc_alt.categoria
FROM ftc_alt;
SELECT catord = ftc_alt.catord
FROM ftc_alt;
SELECT SubCategoria = ftc_alt.subcategoria
FROM ftc_alt;
SELECT subcatord = ftc_alt.subcatord
FROM ftc_alt;
SELECT Ordem = ftc_alt.ordem
FROM ftc_alt;
SELECT CodigoComp = ftc_alt.codigocomp
FROM ftc_alt;
SELECT DesignacaoComp = ftc_alt.designacaocomp
FROM ftc_alt;
SELECT QuantidadeComp = ftc_alt.quantidadecomp
FROM ftc_alt;
SELECT UnidadeComp = ftc_alt.unidadecomp
FROM ftc_alt;
SELECT #intRowCount = ##RowCount;
SET #upAction = 'Composição nutricional actualizada/alterada'
BEGIN
IF (#DataAlteracao = (SELECT CONVERT(DATE, GETDATE())))
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[FichaTecnicaComp]
SET [Codigo] = #Codigo,
[DataAlteracao] = #DataAlteracao,
categoria = ftc_alt.categoria,
catord = ftc_alt.catord,
subcategoria = ftc_alt.subcategoria,
subcatord = ftc_alt.subcatord,
ordem = ftc_alt.ordem,
codigocomp = ftc_alt.codigocomp,
designacaocomp = ftc_alt.designacaocomp,
quantidadecomp = ftc_alt.quantidadecomp,
unidadecomp = ftc_alt.unidadecomp
FROM [dbo].[FichaTecnicaComp]
JOIN ftc_alt ON [dbo].[FichaTecnicaComp].[Codigo] = (SELECT ft_alt.codigo
FROM ft_alt)
AND [dbo].[FichaTecnicaComp].Ordem = (SELECT FTC_Alt.Ordem
FROM FTC_Alt)
END
END
he expected result is that data in FichaTecnicaComp is updated from FTC_Alt.
Which doesn't happen.
It should be noted that the FichaTecnicaComp has the following working triggers: insertion, update and delete.
If you need the code of those triggers just ask.
Sub queries used in this context can only return a single value, whereas your sub queries are just returning all values of the Ordem and codigo columns. Use the columns directly in the ON clause instead of as sub-selects. You will also want use aliases instead of the full table names. Using only the keyword JOIN will default to an INNER JOIN, which is what I'm assuming you intend to use, however explicitly stating this will help with readability. The first sub query in your post uses ft_alt, instead of ftc_alt, but since this is the only reference to this table I'm guessing this is a typo?
BEGIN
SET NOCOUNT ON
UPDATE FTC
SET
FTC.[Codigo] = FT.Codigo,
FTC.[DataAlteracao] = FT.dataalteracao,
FTC.categoria = ALT.categoria,
FTC.catord = ALT.catord,
FTC.subcategoria = ALT.subcategoria,
FTC.subcatord = ALT.subcatord,
FTC.ordem = ALT.ordem,
FTC.codigocomp = ALT.codigocomp,
FTC.designacaocomp = ALT.designacaocomp,
FTC.quantidadecomp = ALT.quantidadecomp,
FTC.unidadecomp = ALT.unidadecomp
FROM [dbo].[FichaTecnicaComp] FTC
INNER JOIN ft_alt FT ON FTC.Codig = FT.Codigo
INNER JOIN ftc_alt ALT ON FTC.Ordem = ALT.Ordem
END
The error message itself says that one of the sub queries used in this stored procedure returns more than one record, while your update statement can handle only one returned row the way it is written. If you run below queries one by one, you will know where is the problem. Either you need to fix the subquery or may need to use IN instead of = in main query. I hope that helps.
(SELECT ft_alt.codigo
FROM ft_alt)
AND
[dbo].[FichaTecnicaComp].Ordem =
(SELECT FTC_Alt.Ordem
FROM FTC_Alt
And also run below independently.
SELECT FTC_Alt.Ordem
FROM FTC_Alt

Subquery returned more than 1 value when trigger executes

I have a trigger which adds a log entry into a table upon a field change in another table. it works when one row is changed but errors when multiple rows re changed. Anyone out there able to explain what I have to do to get my trigger working also for multi row updates?
Many thanks,
Derek
Declare #PropertyID uniqueidentifier
Set #PropertyID = (Select CONVERT(VARCHAR( 36 ), ISNULL(i.[PropertyPK], d.[PropertyPK]))
FROM
INSERTED i
FULL OUTER JOIN DELETED d ON ( d.[PropertyPK] = i.[PropertyPK] )
WHERE
( d.[strManagingOfficeName] <> i.[strManagingOfficeName] ) OR
( d.[strManagingOfficeName] IS NULL AND i.[strManagingOfficeName] IS NOT NULL ) OR
( i.[strManagingOfficeName] IS NULL AND d.[strManagingOfficeName] IS NOT NULL ))
Declare #CompanyID uniqueidentifier
Set #CompanyID = (Select CompanyFK From Property Where PropertyPK = #PropertyID)
--Deleted Old Ones
Delete From TDSAPILog Where ObjectFK = #PropertyID And strObject = 'Branch Change'
--Insert New Log
INSERT dbo.TDSAPILog(TDSAPILogPK, ObjectFK, strObject, strStatus, CompanyFK, dteDateLogged)
SELECT
NewID(),
#PropertyID,
'Branch Change',
'Active',
#CompanyID ,
GetDate()
This error occur when you return more than 1 value from a query and save in a variable or compare with a value in where clause.
In your example I think the error occur at this line
SET #CompanyID = (SELECT CompanyFK FROM Property WHERE PropertyPK = #PropertyID)
To resolve the reported error just put "TOP 1" in your query. Example is shown here:
SET #CompanyID = (SELECT TOP 1 CompanyFK FROM Property WHERE PropertyPK = #PropertyID)
Subquery returned more than 1 value error may occur at the following scenarios:
SET #YouVariable = (SELECT ColumnID FROM yourTable WHERE Identity = #SomeValue)
-- if the above query return more than 1 value the same error will be occurred
-- to resolve this problem just put "TOP 1" before ColumnID
SELECT *
FROM OtherTable
WHERE OtherIdentity = ((SELECT ColumnID FROM yourTable
WHERE Identity = #SomeValue))
-- if the above query return more than 1 value the same error will be occurred
-- to resolve this problem just replace "= with IN()". Example give below
SELECT *
FROM OtherTable
WHERE OtherIdentity IN ((SELECT ColumnID FROM yourTable
WHERE Identity = #SomeValue))

SQL Merge (with Temp Table) failing on SubQuery returned more than 1 value (But I am not using a Sub-Query.. in the update)

I am hoping someone can help me out of this tedium...!?
As the title suggests I have a Temp Table (create dynamically in a select statement):
SELECT *
INTO #results
FROM Table_1
CROSS APPLY ( SELECT TOP 1 *
FROM Table_2
WHERE (Table_1.ItemId = Table_2.ItemId)
ORDER BY CreatedDt DESC
)
... which as you can see uses a Sub-Query in a cross join.
Next I am trying to use this temp table #results to update a related table with its values. have tried using an update:
UPDATE a
SET a.StatusId = b.StatusId
FROM Table_1 a
INNER JOIN #results b on (a.ItemId = b.ItemId)
and with a Merge:
MERGE INTO Table_1 a
USING #results b
ON (a.ItemId = b.temId)
WHEN MATCHED THEN UPDATE SET a.StatusId = b.StatusId;
but I seem to always get a response:
Msg 512, Level 16, State 1, Procedure trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode,
Line 7 [Batch Start Line 11] Subquery returned more than 1 value. This
is not permitted when the subquery follows =, !=, <, <= , >, >= or
when the subquery is used as an expression.
When I query the two tables in question (#results & Table_1) they both have 1 to 1 relationships and cannot see at all where it could be hiding some kind of Subquery!?
Can anyone help quickly on this at all please? This seems to be 1-0-1 stuff and its baking my burger!
-- Edit --
I have taken a look at the Trigger mentioned in the error message as it was suggested it could be trying to handle a single row update instead of a multiple row update which is what I am doing. Nothing looking too unusual to me...?
ALTER TRIGGER [dbo].[trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode]
ON [dbo].[Table_1]
AFTER UPDATE
AS
BEGIN
-- NodeModelInsertOrUpdateTPH
IF ((select [Item] from inserted) = 'X')
BEGIN
UPDATE tx
SET
tx.LastUpdatedBy = i.LastUpdatedBy,
tx.LastUpdatedAt = i.LastUpdatedAt
FROM
[dbo].[Table_X] tx,
inserted i
WHERE
tx.OtherItemId = i.OtherItemId
END
END
Anyone have any ideas?
Your trigger is the issue here. Your IF statement has a query which would return more than 1 row and that exact message would be the result. You should make your trigger tolerant of multiple row operations. Here is the same logic but it can handle any number of rows being updated.
ALTER TRIGGER [dbo].[trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode]
ON [dbo].[Table_1]
AFTER UPDATE
AS
BEGIN
UPDATE tx
SET
tx.LastUpdatedBy = i.LastUpdatedBy,
tx.LastUpdatedAt = i.LastUpdatedAt
FROM
[dbo].[Table_X] tx
join inserted i ON tx.OtherItemId = i.OtherItemId
where i.Item = 'X'
END

Triggers(After UPDATE) cause an error?

I am using sql-server 2012 and i wrote a trigger like this:
ALTER TRIGGER [dbo].[ModValue]
ON [dbo].[Table1]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
declare #ocid bigint
declare #ncid bigint,#pid bigint
set #ocid=(select CategoryId from deleted)
select #ncid=CategoryId,#pid=Id from inserted
if(#ocid<>#ncid)
begin
delete from [Table2] where ProductId=#pid
delete from [Table3] where ProductId=#pid
delete from [Table4] where ProductId=#pid
end
END
When i want to update my table(Table1) i got this error:
Msg 512, Level 16, State 1, Procedure ModValue, Line 15
Subquery returned more than 1 value. This is not permitted when the subquery
follows =, !=, <, <= , >, >= or when the subquery is used as an
expression. The statement has been terminated.
Update query:
update Table1
set sizing = 0
where categoryid = 238
What is wrong with this scripts?
The DELETED and INSERTED tables may contain more than one row.
DELETED - contains data that existed before modifications (old)
INSERTED - modified data (new).
So you have to find out where CategoryID was changed:
...
from
Inserted new
inner join
Deleted old on old.id = new.id
where
new.CategoryID <> old.CategoryID
To do something with that while keeping in mind that there could be many rows, for example:
delete from [Table2] t2
where exists (select 1
from Inserted new
inner join Deleted old on old.id = new.id
where new.CategoryID <> old.CategoryID
and t2.ProductId = d.ProductID)
Note that ProductID could be changed by UPDATE statement too.
I think the following line is the problem:
set #ocid=(select CategoryId from deleted)
SET command expects at most 1 line from the SELECT statement. deleted table may contain more than 1 line, as trigger will fire at batch level, not record level.

Is it possible to have a view in sql-server 2008 that splits one row into many?

The back story is I am trying to write a view that takes a table who's every row is an ID and serialized data for that ID in a clob and presents it in sql navigable form. basically my code looks like:
CREATE VIEW UNSERIALIZED_TABLE_VIEW AS
SELECT
SOURCE_TABLE.ID SOURCE_ID,
a.*
FROM
SOURCE_TABLE,
FUNCTION_WHICH_UNSERIALIZES((SELECT DATA FROM SOURCE_TABLE WHERE ID = SOURCE_ID)
I tried putting the function in the select statement, but that just gave a syntax error about it being undefined. When it runs the error is usually about a subquery returning too many values. I could just unserialize the data in batches, but now I'm really curious what's going wrong.
Example Data
#0History:23:ALPHANUMERICSTUFF1234567ID:11:ACCT1234567SourceMode:6:ANNUAL.ModeChanges:UniqueIndex:23:ALPHANUMERICSTUFF1234567ID:11:ACCT1234567OldValue:1:+NewValue:6:ANNUALChangeType:1:AChangeDate:20:6/03/2013 2:49:32 AM.
#0History:UniqueIndex:95:NOTTHESAME0987654|ALPHANUMERIC534|PRETEND349235|95CHARACTERSID:47:GNR44718500|PNR48CDQ704|PGP48090798|FGDS2345236SourceMode:26:ANNUAL|C-P-D|ANNUAL|ANNUALLoan:3:|||ModeChanges:UniqueIndex:95:00487SOMETHING4264500ORD|992581PROBABLY04ORD|0048SHOULD238BET|0095CHARS436PR638FGP07VDCID:47:GNR44718500|PNR48CDQ704|PGP48090798|FGDS2345236OldValue:7:+|+|+|+NewValue:26:ANNUAL|C-P-D|ANNUAL|ANNUALChangeType:7:A|A|A|AChangeDate:91:12/22/2013 11:53:11 PM|4/22/2013 11:53:11 PM|12/22/2013 11:53:11 PM|12/22/2013 11:53:11 PM.
The data is serialized table data of the form COLUMN_NAME:LENGTH_OF_ENTRY:DATA_FOR_COLUMN_ROW_1|DATA_FOR_COLUMN_ROW2|....NEXT_COLUMN_NAME...
Example of Function:
CREATE FUNCTION FUNCTION_THAT_UNSERIALIZES (#clob varchar(max),#colname varchar(max)) RETURNS #NewValue TABLE (ID INT,value varchar(max)) AS
BEGIN
DECLARE #colstart INT,#lenstart INT,#lenend INT,#collen VARCHAR(MAX),#lngth INT,#tmp VARCHAR(MAX), #rowid INT,#value VARCHAR(max),#next INT;
SELECT
#colstart = CHARINDEX(#colname,#tmp)+1,
#lenstart = CHARINDEX(':',#tmp,#colstart)+1,
#lenend = CHARINDEX(':',#tmp,#lenstart),
#collen = SUBSTRING(#tmp,#lenstart,#lenend - #lenstart),
#lngth = CAST (#collen AS INT),
#tmp = SUBSTRING(#tmp,#lenend,#lngth);
WHILE LEN(#tmp) > 0 BEGIN
SET #next = CHARINDEX('|',#tmp);
IF #next > 0 BEGIN
SET #value = SUBSTRING(#tmp,0,#next);
SET #tmp = SUBSTRING(#tmp,#next+1,LEN(#tmp) - #next);
END ELSE BEGIN
SET #value = #tmp;
SET #tmp = '';
END
INSERT INTO #NewValue VALUES(#rowid,#value)
SET #rowid = #rowid+1;
END
RETURN
Example Error
Msg 512, Level 16, State 1, Line 7
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Msg 4104, Level 16, State 1, Line 15
The multi-part identifier "SOURCE_TABLE.SOURCE_ID" could not be bound.
.. I think there might have been another one, but can't figure out how to reproduce it right this minute.
I think this might be the syntax you need to accomplish what I think you are trying to do.
CREATE VIEW UNSERIALIZED_TABLE_VIEW AS
SELECT
SOURCE_TABLE.ID SOURCE_ID,
a.*
FROM SOURCE_TABLE
CROSS APPLY FUNCTION_WHICH_UNSERIALIZES(DATA, #colname) a
I'm not certain what your #colname parameter should be; it is left out of your code in the question.

Resources