Compilation when Column doesn't exist - sql-server

I've a Stored procedure which looks like this:
create procedure test as
begin
if exists(
select 1 from sys.columns
where Name = N'Column2'
and Object_ID = Object_ID(Table2')
)
select Column2 from Table2
end
I want to run this procedure on db where Column2 doesn't exist. I don't want to take existence check out of SP. Currently the error is :
Msg 207, Level 16, State 1, Procedure test, Line
39 [Batch Start Line 0] Invalid column name 'Column2'.
Is there any way to do so? Why yes and why not?
and why for instance if you check for existence table and select non-existent table that works?

Use dynamic SQL:
create procedure test as
begin
if exists (select 1
from sys.columns
where Name = N'Column2' and Object_ID = Object_ID('Table2')
)
begin
exec sp_executesql N'select Column2 from Table2';
end;
end;

Related

Invalid Object Name for Temp Table in Stored Procedure

I'm trying to use a temp table to update a database table in a stored procedure.
My client was throwing an error about an illegal null value, so I tried testing within SSMS and it told me that the name of the temp table was invalid (regardless of what I named it).
If I run the beginning and change the INSERT INTO SERVICE SELECT S.* to simply SELECT S.* and run the code after Declaring and Defining #OldServicesString (so I can leave out the ALTER/CREATE PROCEDURE line) it runs exactly as expected.
Here's the beginning of the SP:
ALTER PROCEDURE [dbo].[app_CreateNewServicesOldFSD] (#OldServicesStr nvarchar(max)) AS
SET NOCOUNT ON
DECLARE #User char(10) = (SELECT TOP 1 CREATED_BY_USER FROM BATCHLOG WHERE BPROCESS_ID = 3 ORDER BY ID DESC);
DECLARE #LastOldService int = (SELECT MAX(ID) FROM SERVICE);
SELECT TOP 0 * INTO #Service FROM SERVICE;
ALTER TABLE #Service
DROP COLUMN RECNUM;
INSERT INTO #Service exec dbo.app_NewServicesOldFSD
;WITH cteOldFSDsToCreate AS (
SELECT JobID.Item JobID, CONVERT(date,ServDate.Item,103) ServDate
FROM dbo.SplitStringToTable(#OldServicesStr,',',2) JobID
INNER JOIN dbo.SplitStringToTable(#OldServicesStr,',',2) ServDate ON JobID.Rw = ServDate.Rw AND JobID.Cl = 0 AND ServDate.Cl = 1
)
INSERT INTO SERVICE SELECT S.*
FROM #Service S
INNER JOIN cteOldFSDsToCreate N ON N.JobID = S.JOB_ID AND N.ServDate = S.DATE
DROP TABLE #Service
A useable and likely #OldServicesStr could be '11428,23/07/2019,11429,23/07/2019,15186,5/10/2019'
To test it in SSMS I opened a new Query and typed in
exec app_CreateNewServicesOldFSD '11428,23/07/2019,11429,23/07/2019,15186,5/10/2019'
And got the following error:
Warning: Null value is eliminated by an aggregate or other SET operation.
Msg 208, Level 16, State 0, Procedure app_CreateNewServicesOldFSD, Line 65 [Batch Start Line 7]
Invalid object name '#Service'.
Completion time: 2020-11-20T20:36:57.1356921+11:00
I know that is not Your case but in the sake of not forget, there is also a limitation using Biztalk WCF-Custom adapter with SQL Bindings and temp tables.
According to this site :
http://thoughtsofmarcus.blogspot.com/2010/11/calling-stored-procedures-from-biztalk.html
You need to SET FMTONLY OFF before creating temp tables and inserting into them and
SET FMTONLY ON before selecting from them as in example from below.
ALTER PROCEDURE [dbo].[FetchTestData]
(#a4 varchar(4))
AS
DECLARE #FmtOnlyIsSet bit = 0
IF (1=0) BEGIN SET #FmtOnlyIsSet = 1 END
IF #FmtOnlyIsSet = 1
SET FMTONLY OFF
SELECT t1, t2, t3 INTO #temp01 FROM Table_1
IF #FmtOnlyIsSet IS NULL
SET FMTONLY ON
SELECT t1, t2, t3 FROM #temp01
RETURN

Copy column from one table to another table with condition

ALTER PROCEDURE [dbo].[Timesheet_update]
AS
BEGIN
DECLARE #sql2 nvarchar(max), #status nvarchar(1)
SET #sql2 = 'insert into s21022020 (s21_stfno) select m_stfno from master where m_status<>'D''
EXECUTE (#sql2)
END
EXECUTE Timesheet_update
Results in an error:
Msg 207, Level 16, State 1, Line 23
Invalid column name 'D'.
m_status column contain data =D
I don't understand why you feel the need to make this a dynamic SQL - just write the statement directly inside the stored procedure - like this:
ALTER PROCEDURE [dbo].[Timesheet_update]
AS
BEGIN
INSERT INTO s21022020 (s21_stfno)
SELECT m_stfno
FROM master
WHERE m_status <> 'D'
END

Did not find exact example

I am getting this error:
Msg 102, Level 15, State 1, Line 9 Incorrect syntax near '+'.
When executing the following code:
DECLARE #Source nVARCHAR(30)
set #source = 'Srce.srce'
select #Source
--drop table #temp1
select 'xx' col1
INTO #temp
from #Source + .dbo.table1
You can not pass the name of database through variable.
If you want to forward the name of the database using the variable you have to use dynamic SQL.

Why is my sql code throwing errors

Here's the concept: when a user selects a user list from the frontend treeview and clicks the Save button, the table which contains the mapping for role to users must clear itself of all the users with the role and re insert records with the given role id and userlist.
I am using following stored procedure and function:
Stored procedure:
ALTER PROCEDURE [dbo].[AssignRoleToUser]
#RoleID INT = 0,
#UserID varchar(max) = ''
AS
BEGIN
delete from UserRole
where RoleID = #RoleID
AND UserID IN (SELECT UserID FROM UserRole)
INSERT INTO UserRole(UserID, RoleId)
SELECT id, #RoleID
FROM dbo.CSVToTable(#UserID)
END
Function
CREATE FUNCTION [dbo].[CSVToTable] (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE (id int not null)
AS
BEGIN
;-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
But I get this error
Msg 217, Level 16, State 1, Procedure AssignRoleToUser, Line 7
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).
Error is exactly saying what went wrong as below, along with the line number.
Msg 217, Level 16, State 1, Procedure AssignRoleToUser, Line 7
Take out the line 7 from your procedure AssignRoleToUser
INSERT INTO UserRole(UserID, RoleId) SELECT id, #RoleID
FROM dbo.CSVToTable(#UserID)
As can be seen, it's calling another function named dbo.CSVToTable. Likewise dbo.CSVToTable may be calling some other procedure\function and that's how the nesting depth has reached to maximum limit. so the error is.
Also, In Line 6 in your procedure AND UserID IN (Select UserID from UserRole) is not needed. which makes it as below
delete from UserRole where RoleID = #RoleID
You can run the below query which will list out all procedure that gets called in chain when running AssignRoleToUser procedure (Query observed from Get All Nested Stored Procedures)
SELECT * FROM
(SELECT NAME AS ProcedureName, SUBSTRING(( SELECT ', ' + OBJDEP.NAME
FROM sysdepends
INNER JOIN sys.objects OBJ ON sysdepends.ID = OBJ.OBJECT_ID
INNER JOIN sys.objects OBJDEP ON sysdepends.DEPID = OBJDEP.OBJECT_ID
WHERE obj.type = 'P'
AND Objdep.type = 'P'
AND sysdepends.id = procs.object_id
ORDER BY OBJ.name
FOR
XML PATH('')
), 2, 8000) AS NestedProcedures
FROM sys.procedures procs )InnerTab
WHERE NestedProcedures IS NOT NULL
AND NAME = 'AssignRoleToUser'
The error says that you have a call to a procedure, function, or trigger which calls another one which calls another one, etc etc, until the call is 32 calls deep. At this point it's giving and saying 'too much!'.
Do you have any triggers on the UserRole table? Will they call other things? If so, what will they do? And so on...

Microsoft sql stored procedure not executing select statement properly

I'm pretty new to Microsoft T-sql (Use to Oracle PL/SQL) and I ran into a annoying problem with a very simple procedure.
I created the following procedure
CREATE PROCEDURE [dbo].[ele_test] #productId INT
AS
DECLARE #productCode VARCHAR(100);
DECLARE #productDescription VARCHAR(100);
DECLARE #error VARCHAR(100);
--Fetch product
IF #productId != NULL
BEGIN
SELECT #productCode = ProductCode
,#productDescription = ProductDescription
FROM d_afterpay.dbo.Product
WHERE ProductId = #productId
END
IF ##ROWCOUNT = 0
BEGIN
SET #error = 'Product not found: ' + cast(#productId AS VARCHAR(19))
RAISERROR (#error,16,1);
END
And when I run it this way:
exec ele_test 5
I get:
Msg 50000, Level 16, State 1, Procedure ele_test, Line 20
Product not found. Productid : 5
Yet when I run just the query like this:
SELECT * FROM d_afterpay.dbo.Product
WHERE ProductId = 5
I do get a proper result...
Any idea what I am doing wrong?
Your query syntax is slightly wrong, change the query to read:
IF (#productId IS NOT NULL)
instead of using !=
This meant your SELECT statement was never being called hence why the product was always missing.

Resources