Create Insert Trigger - sql-server

This is my code:
USE MyGuitarshop
GO
CREATE TRIGGER Products_INSERT
ON Products
FOR INSERT
AS
BEGIN
UPDATE Products
SET DateAdded = GETDATE()
WHERE DateAdded IS NULL;
END;
GO
USE MyGuitarShop
INSERT INTO Products (CategoryID, ProductCode, ProductName, Description, ListPrice, DiscountPercent, DateAdded)
VALUES (1, '229985', 'Quartz Watch', 'Lovely watch with a quartz face', 29.99, 12, NULL);
GO
USE MyGuitarShop
SELECT * FROM Products
It pops this error: Msg 512, Level 16, State 1, Procedure Products_UPDATE, Line 13 [Batch Start Line 21]
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I don't understand the error or how to fix it. Can someone please point me in the right direction?

You cannot use the regular comparison operators with NULL - anything compared to NULL is undefined and therefore "false".
The only thing you can do to check with NULL is to use IS NULL or IS NOT NULL :
UPDATE Products
SET DateAdded = GETDATE()
WHERE DateAdded IS NULL;

Try
UPDATE inserted SET DateAdded = GETDATE() WHERE DateAdded IS NULL; END;

Related

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

INSERT SELECT SQL Query with Variables

I am trying to INSERT record(s) where some of the fields in the record(s) come from one table and the rest of the fields are created from variables. Here is the INSERT SELECT query where I am trying to create the record(s):
DECLARE #projid INT
,#status INT
,#created DATETIME
,#duedate DATETIME
,#numdays INT
,#divid INT
SET #divid =
(SELECT DIVID
FROM DIV
WHERE StepOrder=1)
SET #numdays =
(SELECT CompTarget
FROM DIV
WHERE DIVID=#divid)
SET #projid = 10
SET #status = 0
SET #duedate =
DATEADD(day,#numdays,#created)
SET #created = '4/18/2017'
INSERT INTO DIVTasks (ProjectID, GroupID, Status, Created, DueDate, DIVID)
SELECT #projid, GroupID, #status, #created, #duedate, DIVID
FROM DIV
WHERE StepOrder=1
There are 3 records with the StepOrder the equals 1 and they have different "CompTarget" numbers.
What I need it to do is take the "Created" date add the "CompTarget" number and return the "DueDate" for each record.
The above query returns this error but does enter 3 records with the "DueDate" as Null:
Msg 512, Level 16, State 1, Line 8
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Both
SET #divid =
(SELECT DIVID
FROM DIV
WHERE StepOrder=1)
and
SET #numdays =
(SELECT CompTarget
FROM DIV
WHERE DIVID=#divid)
will cause the same error, since you wrote there are 3 records with StepOrder equals 1 in that table.
However, I think you are over complicating things.
Try this insert....select instead:
DECLARE #projid INT = 10
,#status INT = 0
,#created DATETIME = '2017-04-18' -- note the change of format here!
INSERT INTO DIVTasks (ProjectID, GroupID, Status, Created, DueDate, DIVID)
SELECT #projid, GroupID, #status, #created, DATEADD(day,CompTarget,#created), DIVID
FROM DIV
WHERE StepOrder=1
Note - using yyyy-mm-dd as the date's string representation format makes it unambiguous.

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.

Stored procedure throws an error on my subquery

My database trigger takes a date from a column and adds 60 days to it and stores it into another column.
And it does as expected when I execute the code in query window and it throws the following error.
Msg 512, Level 16, State 1, Line 4
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
My code:
DECLARE #NextDate date
SELECT #NextDate = (SELECT DATEADD(day, 10, Today) FROM Test)
INSERT INTO Test (Notes, Today)
VALUES ('Testing in Query2', GETDATE())
DECLARE #newint int
SET #newint = SCOPE_IDENTITY()
UPDATE Test
SET Someday = #NextDate
WHERE ID = #newint
RESULT
But keeps giving the error with the result.
Msg 512, Level 16, State 1, Line 4
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
INSERT INTO #NextDate SELECT DATEADD(day,10,Today) FROM Test
In Your Query
SELECT #NextDate = (SELECT DATEADD(day,10,Today) FROM Test)
the sub query returning more than one value and you cant assign the multiple values to one variable. this is causing the problem in you query.
As Dominic Deepan.d Suggested use the where condition
SELECT #NextDate = (SELECT DATEADD(day,10,Today) FROM Test WHERE ID = #newint)
Or else try the same in another way
SELECT #NextDate = DATEADD(day,10,Today) FROM Test WHERE ID = #newint
Well Finally i sorted it out, Silly me :D
INSERT INTO Test(Notes,Today)
values ('Testing in Query3',GETDATE())
DECLARE #newint int
SET #newint = SCOPE_IDENTITY()
DECLARE #NextDate date
SELECT #NextDate = (SELECT DATEADD(day,10,Today) FROM Test WHERE ID = #newint)
UPDATE Test
SET Someday = #NextDate
WHERE ID = #newint
GO
I juz had to put WHERE in this line
SELECT #NextDate = (SELECT DATEADD(day,10,Today) FROM Test WHERE ID = #newint)

MSSQL update multiple rows based on select statement

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;

Resources