Result set not permitted in BATCH STATEMENT - SQL Anywhere - sql

I am new for SQL ANYWHERE. I am passing Table Name as a input parameter. I want to run both delete and select statement .I don't know where I missed my logic. Could you please help me to do this.
My procedure is
ALTER PROCEDURE "dba"."spCallTrigger"(
/* #parameter_name parameter_type [= default_value] [OUTPUT], ... */
#TableName varchar(25) )
AS
BEGIN
/* Type the procedure statements here */
//Exec "dba"."spCallTrigger" 'GTempTable'
SET OPTION ISQL_PRINT_RESULT_SET='ALL';
DECLARE #sql LONG VARCHAR
SET #sql = 'delete from dba.' + #TableName + ' where 1=2'
Execute ( #sql )
DECLARE #command LONG VARCHAR
SET #command = 'select * from dba.' + #TableName + 'Audit'
Execute ( #command )
END

EXECUTE IMMEDIATE WITH RESULT SET ON #command
This might work.

Related

SQL Server Stored Procedure : Dynamic database in query

I have a variable which holds the database that I am working on. How can I add this variable in a static query?
This is what I want to achieve:
if exists(select * from #DestinationDB.[RaPa] where tid = #dyid)
begin
RAISERROR('Rapa exist',16,1)
end
I'm not sure if you meant without Dynamic SQL... but here is how you can accomplish this with dynamic SQL
declare #DestinationDB varchar(64)
declare #dyid int
declare #sql varchar(max)
set #DestinationDB = 'SomeDB'
set #dyid = 14
set #sql =
'if exists(select * from ' + quotename(#DestinationDB) + '.[RaPa] where tid = ' + cast(#dyid as varchar(16)) + ')
begin
RAISERROR(''Rapa exist'',16,1)
end'
print #sql
--exec(#sql)
Just uncomment the exec part when you are satisfied with the command.

Using variables in Transact-sql exists subquery

this seems like it should be extraordinarily simple, so I apologize in advance if this information is easily accessible on the transact-sql documentation pages. I searched myself, but couldn't seem to find anything.
I'm trying to modify a transact-sql statement that currently runs on our Windows server 2000 box. I want to check if a table in another database exists, and then do a bunch of stuff. The database name is given as a string argument, '#dbName'
CREATE PROCEDURE CopyTables
#dbName char(4)
AS
IF EXISTS (SELECT * FROM #dbName.INFORMATION_SCHEMA.TABLES WHERE
TABLE_NAME = N'MainTable')
BEGIN
--Do Stuff
In it's current state, it doesn't like using the bare #dbName variable within the select statement. Is there special syntax for doing this?
Thanks in advance.
The below code should do what you want. As was mentioned previously, the account running the query would need the privilege to query the INFORMATION_SCHEMAs in the target database.
To future-proof your stored procedure, I'd also suggest increasing the length of the database name parameter and declaring it as an nchar or nvarchar in stead of char.
CREATE PROCEDURE CopyTables
#dbName char(4)
AS
DECLARE
#SQLStr nvarchar (max),
#Params nvarchar (max),
#Count tinyint;
SET
#Count = 0;
SET #SQLStr = N'SELECT #qCount = 1 FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N''MainTable''';
SET #Params = N'#qdbName char (4), #qCount tinyint OUTPUT';
EXECUTE sp_executesql #SQLStr, #Params, #qdbName = #dbName, #qCount = #Count OUTPUT;
IF #Count = 1
BEGIN
--Do Stuff
END; -- if
GO
Try doing the following:
DECLARE #dbName NVARCHAR(MAX) = 'master', #TableName NVARCHAR(MAX) = N'spt_monitor';
DECLARE #sql NVARCHAR(MAX) = N'SELECT * FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''' + REPLACE(#TableName,N'''',N'''''') + N'''';
SET NOCOUNT OFF;
EXEC(#sql);
IF ##ROWCOUNT > 0 BEGIN;
-- DO STUFF
SELECT NULL;
END;
There are a few shortcomings to this solution:
1) It requires that the user executing the statement has SELECT access to the other database's INFORMATION_SCHEMA.TABLES
2) It has the side-effect of actually selecting the rows, so if you're using a reader to access the results, you'll have to call reader.NextResult() or await reader.NextResultAsync() because it actually outputs the results of the SELECT statement, rather than doing it in an IF EXISTS context.
By merging the two solutions, we get this:
DECLARE #dbName NVARCHAR(MAX) = 'master', #TableName NVARCHAR(MAX) = N'spt_monitor';
DECLARE #sql NVARCHAR(MAX) = N'SELECT #count = COUNT(*) FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''' + REPLACE(#TableName,N'''',N'''''') + N'''';
DECLARE #Count INT;
EXECUTE sp_executesql #sql, N'#Count INT OUTPUT', #Count OUTPUT;
IF #Count > 0 BEGIN;
-- Do stuff
SELECT 'the table exists';
END ELSE BEGIN;
-- Do stuff
SELECT 'the table does not exist';
END;
This solution requires that the user executing the statement has SELECT access to the other database's INFORMATION_SCHEMA.TABLES, but it does not have the side-effect of selecting rows, like my previous solution.

How to set table name in dynamic SQL query?

I want to set table name in a dynamic SQL query. I tried successfully for parameter as following:
/* Using sp_executesql */
/* Build and Execute a Transact-SQL String with a single parameter
value Using sp_executesql Command */
/* Variable Declaration */
DECLARE #EmpID AS SMALLINT
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
/* set the parameter value */
SET #EmpID = 1001
/* Build Transact-SQL String by including the parameter */
SET #SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeID = #EmpID'
/* Specify Parameter Format */
SET #ParameterDefinition = '#EmpID SMALLINT'
/* Execute Transact-SQL String */
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #EmpID
Now I want to take TABLE NAME dynamically using a parameter but I've failed to do that. Please guide me.
To help guard against SQL injection, I normally try to use functions wherever possible. In this case, you could do:
...
SET #TableName = '<[db].><[schema].>tblEmployees'
SET #TableID = OBJECT_ID(TableName) --won't resolve if malformed/injected.
...
SET #SQLQuery = 'SELECT * FROM ' + QUOTENAME(OBJECT_NAME(#TableID)) + ' WHERE EmployeeID = #EmpID'
Table names cannot be supplied as parameters, so you'll have to construct the SQL string manually like this:
SET #SQLQuery = 'SELECT * FROM ' + #TableName + ' WHERE EmployeeID = #EmpID'
However, make sure that your application does not allow a user to directly enter the value of #TableName, as this would make your query susceptible to SQL injection. For one possible solution to this, see this answer.
Try this:
/* Variable Declaration */
DECLARE #EmpID AS SMALLINT
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
DECLARE #TableName AS NVARCHAR(100)
/* set the parameter value */
SET #EmpID = 1001
SET #TableName = 'tblEmployees'
/* Build Transact-SQL String by including the parameter */
SET #SQLQuery = 'SELECT * FROM ' + #TableName + ' WHERE EmployeeID = #EmpID'
/* Specify Parameter Format */
SET #ParameterDefinition = '#EmpID SMALLINT'
/* Execute Transact-SQL String */
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #EmpID
This is the best way to get a schema dynamically and add it to the different tables within a database in order to get other information dynamically
select #sql = 'insert #tables SELECT ''[''+SCHEMA_NAME(schema_id)+''.''+name+'']'' AS SchemaTable FROM sys.tables'
exec (#sql)
of course #tables is a dynamic table in the stored procedure
Building on a previous answer by #user1172173 that addressed SQL Injection vulnerabilities, see below:
CREATE PROCEDURE [dbo].[spQ_SomeColumnByCustomerId](
#CustomerId int,
#SchemaName varchar(20),
#TableName nvarchar(200)) AS
SET Nocount ON
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
DECLARE #Table_ObjectId int;
DECLARE #Schema_ObjectId int;
DECLARE #Schema_Table_SecuredFromSqlInjection NVARCHAR(125)
SET #Table_ObjectId = OBJECT_ID(#TableName)
SET #Schema_ObjectId = SCHEMA_ID(#SchemaName)
SET #Schema_Table_SecuredFromSqlInjection = SCHEMA_NAME(#Schema_ObjectId) + '.' + OBJECT_NAME(#Table_ObjectId)
SET #SQLQuery = N'SELECT TOP 1 ' + #Schema_Table_SecuredFromSqlInjection + '.SomeColumn
FROM dbo.Customer
INNER JOIN ' + #Schema_Table_SecuredFromSqlInjection + '
ON dbo.Customer.Customerid = ' + #Schema_Table_SecuredFromSqlInjection + '.CustomerId
WHERE dbo.Customer.CustomerID = #CustomerIdParam
ORDER BY ' + #Schema_Table_SecuredFromSqlInjection + '.SomeColumn DESC'
SET #ParameterDefinition = N'#CustomerIdParam INT'
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #CustomerIdParam = #CustomerId; RETURN

Table variable in a stored procedure

I would like to create a simple stored procedure which take as a parameter existing tables.
I thought this procedure should work:
#UserID INT,
#TableName varchar(255)
AS
BEGIN
IF(#UserID is not null)
BEGIN
update t
set t.ProductID = 100
from dbo.[#TableName] t
END
When I execute this stored procedure with a table name, the query completed with errors:
Invalid object name 'dbo.#TableName'.
Any advice?
You'd have to do something like the following:
DECLARE #SQL NVARCHAR(100)
SET #SQL = 'UPDATE ' + #TABLENAME + ' SET t.ProductID = 100 '
EXEC sp_executesql #SQL
Note: You have no WHERE clause so all items in the #TableName will be updated.

Can I pass column name as input parameter in SQL stored Procedure

create procedure sp_First
#columnname varchar
AS
begin
select #columnname from Table_1
end
exec sp_First 'sname'
My requirement is to pass column names as input parameters.
I tried like that but it gave wrong output.
So Help me
You can do this in a couple of ways.
One, is to build up the query yourself and execute it.
SET #sql = 'SELECT ' + #columnName + ' FROM yourTable'
sp_executesql #sql
If you opt for that method, be very certain to santise your input. Even if you know your application will only give 'real' column names, what if some-one finds a crack in your security and is able to execute the SP directly? Then they can execute just about anything they like. With dynamic SQL, always, always, validate the parameters.
Alternatively, you can write a CASE statement...
SELECT
CASE #columnName
WHEN 'Col1' THEN Col1
WHEN 'Col2' THEN Col2
ELSE NULL
END as selectedColumn
FROM
yourTable
This is a bit more long winded, but a whole lot more secure.
No. That would just select the parameter value. You would need to use dynamic sql.
In your procedure you would have the following:
DECLARE #sql nvarchar(max) = 'SELECT ' + #columnname + ' FROM Table_1';
exec sp_executesql #sql, N''
Try using dynamic SQL:
create procedure sp_First #columnname varchar
AS
begin
declare #sql nvarchar(4000);
set #sql='select ['+#columnname+'] from Table_1';
exec sp_executesql #sql
end
go
exec sp_First 'sname'
go
This is not possible. Either use dynamic SQL (dangerous) or a gigantic case expression (slow).
Create PROCEDURE USP_S_NameAvilability
(#Value VARCHAR(50)=null,
#TableName VARCHAR(50)=null,
#ColumnName VARCHAR(50)=null)
AS
BEGIN
DECLARE #cmd AS NVARCHAR(max)
SET #Value = ''''+#Value+ ''''
SET #cmd = N'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + #Value
EXEC(#cmd)
END
As i have tried one the answer, it is getting executed successfully but while running its not giving correct output, the above works well
You can pass the column name but you cannot use it in a sql statemnt like
Select #Columnname From Table
One could build a dynamic sql string and execute it like EXEC (#SQL)
For more information see this answer on dynamic sql.
Dynamic SQL Pros and Cons
As mentioned by MatBailie
This is much more safe since it is not a dynamic query and ther are lesser chances of sql injection . I Added one situation where you even want the where clause to be dynamic . XX YY are Columns names
CREATE PROCEDURE [dbo].[DASH_getTP_under_TP]
(
#fromColumnName varchar(10) ,
#toColumnName varchar(10) ,
#ID varchar(10)
)
as
begin
-- this is the column required for where clause
declare #colname varchar(50)
set #colname=case #fromUserType
when 'XX' then 'XX'
when 'YY' then 'YY'
end
select SelectedColumnId from (
select
case #toColumnName
when 'XX' then tablename.XX
when 'YY' then tablename.YY
end as SelectedColumnId,
From tablename
where
(case #fromUserType
when 'XX' then XX
when 'YY' then YY
end)= ISNULL(#ID , #colname)
) as tbl1 group by SelectedColumnId
end
First Run;
CREATE PROCEDURE sp_First #columnname NVARCHAR(128)--128 = SQL Server Maximum Column Name Length
AS
BEGIN
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT ' + #columnname + ' FROM Table_1'
EXEC(#query)
END
Second Run;
EXEC sp_First 'COLUMN_Name'
Please Try with this.
I hope it will work for you.
Create Procedure Test
(
#Table VARCHAR(500),
#Column VARCHAR(100),
#Value VARCHAR(300)
)
AS
BEGIN
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #Table + ' WHERE ' + #Column + ' = ' + #Value
--SELECT #sql
exec (#sql)
END
-----execution----
/** Exec Test Products,IsDeposit,1 **/