SQL Server Sub query with multiple results - sql-server

I am attempting to populate an existing bridge table from a table that exists as a template for how items are populated into the bridge table.
I am attempting to do a new insert into the bridge table (dbo.ECN_ChecklistItem) where the list of items from dbo.ECN_ChecklistItem (SELECTed by ECNID (a foreign key ID)) differs from dbo.BusinessUnit_ChecklistItem (SELECTed by BusinessUnit and InUse).
I get a SQL exception stating that "Sub query returned more than 1 value. This is not permitted when the sub query follows follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
I have attempted to modify the query to include an 'in' operator rather than a '=' operator, however that was not successful either. I may have done it incorrectly.
CREATE PROCEDURE checkCurrentChecklistItemsAgainstInUseItems
--Parameters
#ECNID INT, --I need the ECNID to do the search properly.
#BU NVARCHAR(50),
#Date NVARCHAR(10), --This is the date that the checklist item was added to the ECN.
#NewStatus NVarchar(3) --This is based off of the status of the ECN, will either be '?' or 'No'
AS
BEGIN
DECLARE #System NCHAR(6)='SYSTEM'
DECLARE #Message NVARCHAR(50) = 'This value was added by the system automatically.'--Not in use.
SET NOCOUNT ON;
INSERT INTO dbo.ECN_ChecklistItem (ECNID, Required, LogBy, LogDate, Description, CheckName)
VALUES(#ECNID, #NewStatus, #System, #Date, NULL,
(Select ChecklistItem FROM dbo.BusinessUnit_ChecklistItem WHERE BusinessUnit Like #BU
EXCEPT SELECT CheckName FROM dbo.ECN_ChecklistItem WHERE ECNID Like #ECNID))
END
GO

The rest of the Insert Statement is towards a single row. However, the subquery might be returning (or has the possibility of returning) multiple rows. Whenever this situation occurs, SQL Server puts up this.
You might want to examine, by running the subquery separately as a query to find whether multiple rows are being returned even as you "assume" that there will be only row returned.
If it does indeed multiple rows, then you will need to handle that situation separately depending on your logic.
However, if you are sure only one row is being returned, you can always a MAX or MIN or TOP 1 . Although they are inconsequential when a single row is being returned, they will avoid the 'subquery returned mutliple' error.
Edit :
If you indeed want multiple rows to be inserted, replace the Values phrase, with the complete select phrase, with values for all the other fields remaining as fixed values (# ones), and the value for CheckName coming from the select statement. Select #..., #..., #...., .... CheckListItem From .... Where BusinessUnit Like ... Except... and so on.

Related

Insert into temp table from SELECT giving strange error

EDIT: I have since been corrected that I need to be doing an update to achieve my intended results. At this point, I'm not able to get the UPDATE statement to do what I want it to, despite my select statement giving me exactly what I want.
begin tran
update #cal1
set calendar_key =
(
SELECT 16801 - 1 + ROW_NUMBER() OVER (
PARTITION BY 1 ORDER BY CalendarDate
) )
FROM #cal1
The results from this give me a repeating 16801 in this column as opposed to going down through the numbers as in my select statement. What am I doing wrong here?
Well, the error seems rather clear and obvious: since you're not specifying the Holiday column in your INSERT statement (in the list of columns you're inserting into), no value is being inserted into Holiday - this is stays NULL.
And it appears from the error message that the Holiday does not allow NULL - you need to explicitly provide a value!
INSERT INTO #cal1 (calendar_key, Holiday)
SELECT
16801 - 1 + ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY CalendarDate) AS count,
-some-value-for-holiday-here-
FROM #cal1
Other than explicitly providing a value, you could also:
Make the Holiday column nullable, so it would be fine with a NULL
Provide a default constraint for Holiday, so that if you don't provide a value, the defined default will be used instead
UPDATE:
Seeing that you say
The problem here is that the other values are as they should be. Is there not a way I can add data to just this one column?
Do you really want to INSERT a new row?? Or would you much rather want to UPDATE an existing row and set just that calendar_key column's value?? In that case, you need an UPDATE statement - not an INSERT ......

Cannot insert 'NULL' value into SQL Server column

I have a table that is filled using a stored procedure. This stored procedure uses a view that calls attributes from another databases.
To illustrate, it is something like:
ALTER PROCEDURE theSp
AS BEGIN
INSERT INTO dbo.theTable (attr1, att2, amount, attr4)
SELECT attr1, attr2, amount, attr4
FROM theView
END
The view is defined this way:
select attr1, attr2, amount, attr4
from db1.theTable
where date >='anyDate'
and the values are correctly inserted, but if the view is used this way:
select attr1, attr2, amount, attr4
from db2.theTable
where date >='anyDate'
this message is shown:
Checking identity information: current identity value '1252'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Msg 515, Level 16, State 2, Procedure theSp, Line 16
Cannot insert the value NULL into column 'amount', table 'db2.dbo.theTable'; column does not allow nulls. INSERT fails.
Note: the 'amount' attribute for db1 and db2 tables allows null but I never insert null, instead, I insert 0.
So I filtered to check whether the amount attribute is null and I did not get results, meaning there are not nulls value in the amount attribute.
Does anyone know a possible solution?
By looking at the error message that you have posted
Cannot insert the value NULL into column 'amount', table 'db2.dbo.theTable'; column does not allow nulls. INSERT fails. The statement has been terminated.
there is a Null value for amount column in `db2.dbo.theTable'. You can use ISNULL() to get rid of this issue.
If you want to see the NULL values, you gotta use query like
select * from db2.dbo.theTable where amount IS NULL
Have a look at is Null vs =Null to see why you weren't seeing those null records in your previous query.
Good to have a logger to validate the condition when it's going wrong, like printing the values before inserting

SQL server GetDate in trigger called sequentially has the same value

I have a trigger on a table for insert, delete, update that on the first line gets the current date with GetDate() method.
The trigger will compare the deleted and inserted table to determine what field has been changed and stores in another table the id, datetime and the field changed. This combination must be unique
A stored procedure does an insert and an update sequentially on the table. Sometimes I get a violation of primary key and I suspect that the GetDate() returns the same value.
How can I make the GetDate() return different values in the trigger.
EDIT
Here is the code of the trigger
CREATE TRIGGER dbo.TR
ON table
FOR DELETE, INSERT, UPDATE
AS
BEGIN
SET NoCount ON
DECLARE #dt Datetime
SELECT #dt = GetDate()
insert tableLog (id, date, field, old, new)
select I.id, #dt, 'field', D.field, I.field
from INSERTED I LEFT JOIN DELETED D ON I.id=D.id
where IsNull(I.field, -1) <> IsNull(D.field, -1)
END
and the code of the calls
...
insert into table ( anotherfield)
values (#anotherfield)
if ##rowcount=1 SET #ID=##Identity
...
update table
set field = #field
where Id = #ID
...
Sometimes the GetDate() between the 2 calls (insert and update) takes 7 milliseconds and sometimes it has the same value.
That's not exactly full solution but try using SYSDATETIME instead and of course make sure that target table can store up datetime2 up to microseconds.
Note that you can't force different datetime regardless of precision (unless you will start counting up to ticks) as stuff can just happen at the same time wihthin given precision.
If stretching up to microseconds won't solve the issue on practical level, I think you will have to either redesign this logging schema (perhaps add identity column on top of what you have) or add some dirty trick - like make this insert in try catch block and add like microsecond (nanosecond?) in a loop until you insert successfully. Definitely not s.t. I would recommend.
Look at this answer: SQL Server: intrigued by GETDATE()
If you are inserting multiple ROWS, they will all use the same value of GetDate(), so you can try wrapping it in a UDF to get unique values. But as I said, this is just a guess unless you post the code of your trigger so we can see what you are actually doing?
It sounds like you're trying to create an audit trail - but now you want to forge some of the entries?
I'd suggest instead adding a rowversion column to the table and including that in your uniqueness criteria - either instead of or as well as the datetime value that is being recorded.
In this way, even if two rows are inserted with identical date/time data, you can still tell the actual insertion order.

Update zipcode to Pad with Zeros in SQL SERVER 2012

I have a table with a Zipcode column.
The Zipcode column is an int.
How to I update this column to show padded zeros such that all values are 5 digits?
I know how to do this as a SELECT statement, but I don't know how to then update the coulmn in the table. Below is my best effort.
USE RTCA_new
GO
UPDATE tbl_BASE
SET Zipcode = (
SELECT FORMAT(Zipcode, '00000')
FROM rtca.tbl_BASE
)
The resulting error is:
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.
In short, I would like a zipcode value 802 to display as 00802
As you've probably figured out, zip codes can start with 0. integers in sql server do not allow for 0 padding.
I see your options as:
always padding it in the select
changing the column type to a more appropriate varchar and padding that with 0s up to 5 characters. (you should do this preferably)
Steps for new columns:
Create new varchar(5) column for zipCode (newZipCode as example)
populate the newZipCode column as:
update tbl_base
set newZipCode = right('00000' + cast(zipCode as varchar(5)), 5)
drop your int zipcode column
rename your newZipCode column to zipCode
The specific reason for your error:
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.
In the query:
UPDATE tbl_BASE
SET Zipcode = (
SELECT FORMAT(Zipcode, '00000')
FROM rtca.tbl_BASE
)
Is because you have a logic error or similar in your statement. you're attempting to set a scalar value (ZipCode) to a set's value (your select format... statement.)
the statement:
SELECT FORMAT(Zipcode, '00000')
FROM rtca.tbl_BASE
by itself would return a row for every row in the table, you can't set a whole result set to a scalar value. The immediate error can be fixed as so:
UPDATE tbl_BASE
SET Zipcode = FORMAT(Zipcode, '00000')
this would return a single value for zipcode... though again due to your current table schema, this would not give you the result you're hoping as integers can't be padded with 0s
It works different:
Update tbl_BASE set zipcode = right('000000' + zipcode, 6)
It's probably best to change the database design if possible (even though you might save a tiny bit of storage in the row by not using a string value.) If you do just need to convert it only for display purposes it's just a question of conversion.
select right('00000' + cast(zipcode as varchar(5)), 5) from T...
-- for use format() on later editions of SQL Server
By the way I would still recommend doing some reading about update to explore why you didn't really want a subquery for what you were trying to accomplish.
You could add a computed column to the table if you need this conversion to happen on the fly. Seeing that you were trying to update a column with a formatted value is probably evidence that the biggest problem was indeed a misunderstanding of data types as has already been pointed out.
You will need to change your datatype for the Zipcode column to varchar. Once you do that, you could use replicate, concat and right functions to format your data:
UPDATE tbl_BASE
SET zipcode = right(CONCAT(
replicate('0', 5)
,cast(zipcode as varchar(5))
), 5)

Stored procedure error .. Inserting columns from one table to another

I have stored procedure in which i am trying to insert two columns in a table, value of one column is from another table and the value of second column is constant and passed in the parameter.
I think i will have to use a loop of somekind but I have no idea how. Kindly help
MY stored Procedure
CREATE PROCEDURE sp_MTS_MTS_MemberTracking_request
-- Add the parameters for the stored procedure here
#monthYear datetime
AS
select [MemberId] from [dbo].[MTS_Members] where Is_Active='true'
insert into [dbo].[MTS_MemberTracking] (MemberId,MonthYear)values ((select [MemberId]
from [dbo].[MTS_Members]
where Is_Active='true'),#monthYear)
Error
Msg 512, Level 16, State 1, Line 1
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.
Since there can be more than one record in MTS_Members having Is_Active='true' you can't insert it using insert... values syntax.
If you really want to insert IDs of all "active" records then just change your query to:
insert into [dbo].[MTS_MemberTracking] (MemberId,MonthYear)
select [MemberId], #monthYear
from [dbo].[MTS_Members]
where Is_Active='true'
or, if it should be exactly one record to insert - you have to change where condition of your select to return exactly one MemberId, store that ID in some variable and use in insert... values construction.

Resources