sp_refreshsqlmodule is failing with UNION, INTERSECT or EXCEPT operator must have an equal number of expressions error - sql

I have written one stored procedure where I have added UNION like this:
SELECT *,SysStartTime, SysEndTime FROM dbo.FirstTable WHERE Id = #Id
UNION
SELECT * FROM history.FirstTable WHERE Id = #Id
where dbo.FirstTable is temporal table and history.FirstTable is it's history table.
If I write a query like:
exec sp_refreshsqlmodule N'USP_MySPName'
It fails with below error:
Msg 205, Level 16, State 1, Procedure sys.sp_refreshsqlmodule_internal, Line 85 [Batch Start Line 0]
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
However if I alter it, it doesn't show any error. And even while execution it doesn't show any error. Even if I execute the above query separately it works fine.
I tried searching for the cause of this error but I m not able to find any reference.
Can someone help me with the reason for this error.
NOTE: This error can be fixed with manually specifying all the column names from both tables instead if using *

Related

SQL Code Evaluation stopping a valid transaction

As part of the company I am working for at the moment I need to create some database upgrade scripts to replace some work of a previous contractor.
The code before the following block runs, creates the new ID column, and then this script looks to populate the values and then drop some columns.
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Name')
and
EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Code')
BEGIN
UPDATE
[Central].[Core.Report].[ReportLessonComp]
SET
CompetencyId = rc.Id
FROM
[Central].[Core.Report].[ReportLessonComp] rlc
INNER JOIN
[Core.Lookup].ReportCompetency rc
ON
rc.Code = rlc.Code and rc.Name = rlc.Name
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN CODE
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Name]
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Description]
END
GO
When running the if exists \ not exists checks and then select getdate() this works perfeclty fine and gives me the result I expect.
However, when I run the code block above I get error
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Code'.
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Name'.
This script it part of a larger upgrade script and is used in a system calle RoundHouse https://github.com/chucknorris/roundhouse which is the system chosen by the company.
Prior to the above if exists check,
IF (SELECT COUNT(1) FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID('[Central].[Core.Report].[ReportLessonComp]')
AND Name in ('Name','Code')) = 2
which also gave the same issue. I have five tables that I need to update and this is going to stop the team from working if I cant resolve this at my next PR
What can I do in order to stop this from causing the upgrade scripts to fail?
EDIT -- The reason I am linking on varchar fields also is because the previous developer did not create relationships between tables, and was just inserting strings into tables rather than relating by ID causing the potential for unlinked \ inconsistent data.
The table edit prior to this creates the new id column, and this script is getting the value and dropping columns that are no longer needed
SQL Server will parse the whole of the statement prior to execution, so the exists check does not protect you from the update being parsed. If the column has already been dropped, that makes the statement invalid and you get a parse error. The update statement would have to be executed as dynamic SQL, sp_execute basically so that the varchar of the update is not directly parsed.
For SQL Server 2016 and above the drop column can be protected a bit more as well:
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN IF EXISTS CODE

msg 8152 level 16 state 2 string or binary data would be truncated

I am getting this error while executing a procedure
Msg 8152, Level 16, State 2, Procedure SP_xxxxx, Line 92 String or
binary data would be truncated.
I have created a temp table which I will load the data from main table once in procedure and I would be using this table not the main table as main table has huge volume of data and many unnecessary columns.
When I run the below code from sql server management studio then there is no error but when I run this code from a procedure then their is the above error message.
Insert into abc_TMP // tmp for procedure with required columns
Select
Item,
Description,
size,
qty,
stock,
Time ,
Measure
from abc // main table has many columns
One way to check this issue, is to see length of each value
Assume you have table like below
create table t
(
col1 varchar(10),
col2 varchar(10)
)
Inserts into the table will fail,if you try to insert more than 10 characters,if you try to insert them in a batch, you will not get offending value.
So you need to check its length like below , prior to insert
;with cte
as
(
select
len(col1) as col1,
len(Col2) as col2
from table
)
select * from cte where col2>10
There has been number of requests raised with Microsoft to enhance error message and they have finally fixed this issue in SQL2019.
Now you can get the exact value causing the issue
References:
https://voiceofthedba.com/2018/09/26/no-more-mysterious-truncation/
I suspect that you are looking at the wrong line of code in the stored proc.
When you open the proc, i.e. ALTER... you have a header on the stored proc that will throw the line number out.
If you run this, replacing proc_name with your procedure name:
sp_helptext proc_name
That will give you the code that the procedure will actually run, with accurate line numbers if you paste it into a new window.
Then you'll see where the actual error is happening.
If you want a simple way to prove this theory, put a bunch of Print 'some sql 1', Print 'some sql 2' lines in around the code you think is causing the error and see what is output when the error is thrown.

Early execution of "sp_rename" causes query to fail

I'm having a strange problem with an MSSQL Query that I'm trying to run in Microsoft SQL Server 2014. It is an update script for my database structure. It should basically rename a Column (from Price to SellingPrice) of a Table after its content was merged to another one.
USE db_meta
GO
DECLARE #BakItemPrices TABLE
(
ItemNum int,
Price int,
CashPrice int
)
-- backup old prices
insert into #BakItemPrices
select ItemNum, Price from dbo.ItemInfo
-- merge into other table
alter table ShopInfo
add column Price int NOT NULL DEFAULT ((0))
update ShopInfo
set ShopInfo.Price = i.Price
from ShopInfo s
inner join #BakItemPrices i
on s.ItemNum = i.ItemNum
GO
-- rename the column
exec sp_rename 'ItemInfo.Price', 'SellingPrice', 'COLUMN' -- The Debugger executes this first
GO
This query always gave me the error
Msg 207, Level 16, State 1, Line 13
Invalid column name 'Price'.
I couldn't understand this error until I debugged the query. I was amazed as I saw that the debugger wont even hit the breakpoint I placed at the backup code and says that "its unreachable because another batch is being executed at the moment".
Looking further down I saw that the debugger instantly starts with the exec sp_rename ... line before it executes the query code that I wrote above. So at the point my backup code is being executed the Column is named SellingPrice and not Price which obviously causes it to fail.
I thought queries get processed from top to bottom? Why is the execute sequence being executed before the code that I wrote above?
Script is sequenced from top to down. But some changes to schema is "visible" after the transaction with script is committed. Split your script into two scripts, it can help.

OPENQUERY throws error when used with WIN2K8\SQL2K12

I'm trying the following Sql query to move my stored procedure result into table
SELECT *
INTO #tmpTable
FROM OPENQUERY(WIN2K8\SQL2K12, 'EXEC vcs_gauge #gauge_name=vs1_bag,#first_rec_time=2014-09-01 09:00:00,#last_rec_time=2014-09-01 10:00:00')
following error is thrown, when I execute the query.
Incorrect syntax near '\'.
I don't want to add linked server .How to resolve this issue?
EDIT1
When I do [win2k8\sql2k12], and first execute the following command
EXEC sp_serveroption 'YourServer', 'DATA ACCESS', TRUE
A new message comes
OLE DB provider "SQLNCLI11" for linked server "WIN2K8\SQL2K12" returned message "Deferred prepare could not be completed.".
Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '-'.
You need to enclose DATETIME values in single quotes. And since your query is in a string itself, those single-quotes need to be doubled / escaped as follows (and you should probably also put the first parameter's value in escaped-single-quotes as it is clearly a string).
You should also fully qualify the stored procedure name with [DatabaseName].[SchemaName]..
And since the vcs_gauge proc uses Dynamic SQL, you need to specify the WITH RESULT SETS clause. For more info on this clause, please see the MSDN page for EXECUTE.
SELECT *
INTO #tmpTable
FROM OPENQUERY([WIN2K8\SQL2K12],
N'EXEC [DatabaseName].[SchemaName].vcs_gauge
#gauge_name = ''vs1_bag'',
#first_rec_time = ''2014-09-01 09:00:00'',
#last_rec_time = ''2014-09-01 10:00:00''
WITH RESULT SETS ( { column_specification} );
');

Stored Procedure consist Add column, Update data for that column, and Select all data from that table

I've written a stored procedure as following:
CREATE PROC spSoNguoiThan
#SNT int
AS
begin
IF not exists (select column_name from INFORMATION_SCHEMA.columns where
table_name = 'NhanVien' and column_name = 'SoNguoiThan')
ALTER TABLE NhanVien ADD SoNguoiThan int
else
begin
UPDATE NhanVien
SET NhanVien.SoNguoiThan = (SELECT Count(MaNguoiThan)FROM NguoiThan
WHERE MaNV=NhanVien.MaNV
GROUP BY NhanVien.MaNV)
end
SELECT *
FROM NhanVien
WHERE SoNguoiThan>#SNT
end
GO
Then I get the error :
Server: Msg 207, Level 16, State 1, Procedure spSoNguoiThan, Line 12
Invalid column name 'SoNguoiThan'.
Server: Msg 207, Level 16, State 1, Procedure spSoNguoiThan, Line 15
Invalid column name 'SoNguoiThan'.
Who can help me?
Thanks!
When the stored proc is parsed during CREATE the column does not exist so you get an error.
Running the internal code line by line works because they are separate. The 2nd batch (UPDATE) runs because the column exists.
The only way around this would be to use dynamic SQL for the update and select so it's not parsed until EXECUTE time (not CREATE time like now).
However, this is something I really would not do: DDL and DML in the same bit of code
I ran into this same issue and found that in addition to using dynamic sql I could solve it by cross joining to a temp table that had only one row. That caused the script compiler to not try to resolve the renamed column at compile time. Below is an example of what I did to solve the issue without using dynamic SQL
select '1' as SomeText into #dummytable
update q set q.ValueTXT = convert(varchar(255), q.ValueTXTTMP) from [dbo].[SomeImportantTable] q cross join #dummytable p