Snowflake Stored Procedure Use Statement - snowflake-cloud-data-platform

I am working with a Snowflake stored procedure that will take a view that is changed from one database to another one. I am trying
var sqlCommand = `
SELECT a.OBJECT_NAME, a.OBJECT_SCHEMA, a.OBJECT_TYPE, d.VIEW_DEFINITION
FROM VIEW_OBJECT_LIST a
INNER JOIN DB_DEV.INFORMATION_SCHEMA.VIEWS d ON a.OBJECT_NAME = d.TABLE_NAME AND a.OBJECT_SCHEMA = d.TABLE_SCHEMA
INNER JOIN DB_QA.INFORMATION_SCHEMA.VIEWS q ON a.OBJECT_NAME = q.TABLE_NAME AND a.OBJECT_SCHEMA = q.TABLE_SCHEMA AND d.VIEW_DEFINITION != q.VIEW_DEFINITION;`;
var viewList = snowflake.createStatement({ sqlText: sqlCommand}).execute();
while(viewList.next()){
var sql = viewList.VIEW_DEFINITION;
var sql = 'USE DB_QA; ' || sql;
snowflake.createStatement({ sqlText: sql }).execute();
}
but getting the error message
Unsupported statement type 'USE'. At Statement.execute
Is there a way in a Snowflake stored procedure to be able to run a USE statement as part of a call to the Snowflake API?

what is the execute permission you are using while creating this stored procedure?
If you are using "EXECUTE AS OWNER" in the create procedure statement then you might not be able to use the statements other than below statements :->
Restrictions on SQL Statements
Although caller’s rights stored procedures can execute any SQL statement that the caller has sufficient privileges to execute outside a stored procedure, owner’s rights stored procedures can call only a subset of SQL statements.
The following SQL statements can be called from inside an owner’s rights stored procedure:
SELECT.
DML.
DDL. (See above for restrictions on the ALTER USER statement.)
GRANT/REVOKE.
Variable assignment.
DESCRIBE and SHOW. (See limitations documented above.)
Other SQL statements cannot be called from inside an owner’s rights stored procedure.
Please try creating same procedure using "EXECUTE AS CALLER" this allows snowflake native sql commands like LIST, USE DATABASE,RM, etc.

I believe the only issue is that you have not defined what DB_QA is in your USE statement. I assume its the name of a database, so you just need to modify that line to be:
var sql = 'USE DATABASE DB_QA; ' || sql
I am not sure whether snowflake.createStatement allows for a multi-statement query to be passed in, though. You'll have to let me know if that works.

Related

How to use output parameter in SSIS execute sql task from a stored procedure

Using a parameter, #IsSuccess in stored proc. How to use that #IsSuccess parameter in SSIS Execute SQL Task and take that as output from that component to another component?
You should use the following SQL statement in the Execute SQL Task to store the stored procedure output into an SSIS variable:
EXEC mystoredprocedure ? OUTPUT
Then in the Execute SQL Task editor, go to the parameter mapping form and select the SSIS variable you need to store that value.
More details can be found in the following article:
Execute SQL Task in SSIS: Output Parameters vs Result Sets
After storing that value, you should use this variable within the precedence constraints expressions:
Overview of SSIS Precedence Constraints

Snowflake:Automate Cloning Process

Requirement: I am looking at how to automate the cloning process from Prod to dev every day
Either Python or Stored Procedure
You can clone a database with a single-line SQL statement; however, I tested running that in a SQL stored procedure and it will not run create statements in SQL stored procedures. A JavaScript stored procedure will work.
Since all Snowflake tasks require a stored procedure to run, you'll need a JavaScript stored procedure if you want to use tasks.
Here's a sample:
-- Recommend you do not store the SP in a database you'll be cloning
create or replace procedure UTIL_DB.PUBLIC.CLONE_MY_DB()
returns string
language javascript
as
$$
return executeNonQuery('create or replace database TEST2 clone TEST1');
function executeNonQuery(queryString) {
var out;
cmd1 = {sqlText: queryString};
stmt = snowflake.createStatement(cmd1);
var rs;
rs = stmt.execute();
rs.next();
return rs.getColumnValue('status');
return out;
};
$$;
-- Make sure the SP works
drop database if exists TEST2;
call UTIL_DB.PUBLIC.CLONE_MY_DB();
-- Create a task calling the SP.
-- Use CRON syntax to get productionized
-- https://docs.snowflake.com/en/sql-reference/sql/create-task.html
create task MY_CLONE_TASK
warehouse = TEST
schedule = '1440 minute'
as call UTIL_DB.PUBLIC.CLONE_MY_DB();
Remember that your task is not enabled by default. You'll need to do something like this for the role you want to run the task:
use role ACCOUNTADMIN;
grant execute task on account to role SYSADMIN;
use role SYSADMIN;
alter task UTIL_DB.PUBLIC.MY_CLONE_TASK resume;
Since you make reference to cloning, I will assume that your Prod and Dev environments are in the same Snowflake account. You could this pretty easily with a task that simply drops the DEV database and then clones the PROD database. I don't think you need an SP or Python for this.

How to get name of executing stored procedure in Snowflake?

Does snowflake have function which returns name of the current stored procedure like the following in SQL Server.
SELECT OBJECT_NAME(##PROCID)
I am just trying to build a logging table to log all statements that are executed inside a stored procedure this is for monitoring purpose i.e. which statement within stored procedure failed and how long queries are taking to run. If Snowflake has something out-of-box OR a recommended way of doing it please share.
Try this from within your stored procedure:
const procName = Object.keys(this)[0];
Also see this related post.

How to drop temp tables created in snowflake

I am loading data through ODI into snowflake temp tables created with c$ needs to be dropped after load successful,how to drop those temp tables appreciate your suggestion
If you still need this, I wrote a stored procedure that will take a list of SQL generated dynamically and execute the lines one at a time. You can use it to run any list of generated SQL statements resulting from a select query, including dropping all tables matching a pattern such as c$%. First, here's the stored procedure:
create or replace procedure RunBatchSQL(sqlCommand String)
returns string
language JavaScript
as
$$
/**
* Stored procedure to execute multiple SQL statements generated from a SQL query
* Note that this procedure will always use the column named "SQL_COMMAND"
*
* #param {String} sqlCommand: The SQL query to run to generate one or more SQL commands
* #return {String}: A string containing all the SQL commands executed, each separated by a newline.
*/
cmd1_dict = {sqlText: SQLCOMMAND};
stmt = snowflake.createStatement(cmd1_dict);
rs = stmt.execute();
var s = '';
while (rs.next()) {
cmd2_dict = {sqlText: rs.getColumnValue("SQL_COMMAND")};
stmtEx = snowflake.createStatement(cmd2_dict);
stmtEx.execute();
s += rs.getColumnValue(1) + "\n";
}
return s;
$$
You can use this stored procedure to run any dynamically generated SQL statements in batch using the following script. Run the topmost query and it will be obvious what running the stored procedure with that query test as the parameter will do:
-- This is a select query that will generate a list of SQL commands to execute in batch.
-- This SQL will generate rows to drop all tables starting with c$. With minor edits
-- you could limit it to a specific database or schema.
select 'drop table ' || TABLE_CATALOG || '.' || TABLE_SCHEMA || '.' || "TABLE_NAME" as SQL_COMMAND
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME like 'c$%';
-- As a convenience, this grabs the last SQL run so that it's easier to insert into
-- the parameter used to call the stored procedure.
set query_text = ( select QUERY_TEXT
from table(information_schema.query_history(result_limit => 2))
where SESSION_ID = Current_Session() and QUERY_TYPE = 'SELECT' order by START_TIME desc);
-- Confirm that the query_text variable has the correct SQL query to generate our SQL commands (grants in this case) to run.
select $query_text;
-- Run the stored procedure. Note that to view its output better, double click on the output to see it in multi-line format,
Call RunBatchSQL($query_text);
--Check the last several queries run to make sure it worked.
select QUERY_TEXT
from table(information_schema.query_history(result_limit => 100))
where SESSION_ID = Current_Session() order by START_TIME desc;
The C$ prefixed work tables are a product of ODI use, but they are not created as actual Snowflake temporary tables so they do not benefit from an automatic deletion at JDBC session termination.
The ODI publishers note this about their C$ and I$ work tables:
When a scenario successfully completes, it will automatically delete these tables, as they're transitory and are no longer required. However, where a scenario does not complete successfully, it is possible these tables get left behind and from time to time it maybe desirable to clean up these tables to reclaim space.
For unsuccessful scenarios in your use of ODI that is likely leading to leftover tables on Snowflake, following the link above should help you run a procedure that deletes the leftover work tables (manually or on a schedule). Copying over the relevant procedure here for convenience:
To run the procedure:
Open ODI Studio and connect to the BI Apps ODI Repository.
Navigate to the Designer tab and use the navigator to navigate to: BI Apps Project -> Components -> DW -> Oracle -> Clean Work and Flow Tables folder
In the folder find the Clean Work and Flow Tables package and in this package is the UTILITIES_CLEAN_WORK_AND_FLOW_TABLES scenario.
Right click the scenario and select the 'Execute' option. At the prompt, provide the desired number of days to go back before deleting tables

drop and create SQL Server procedure

I'm trying to drop and create a procedure in a single script. I tried this:
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'Foo')
DROP PROCEDURE Foo
GO
CREATE PROCEDURE dbo.Foo
-- procedure body here
But I get an error:
Incorrect syntax near 'GO'.
If I remove GO, I get an error:
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch
Update
These scripts are being executed by a Java build tool (Maven)
GO is not actually a valid term in T-SQL, it's merely the separator that the Microsoft management tools use to delimit query batches.
What are you using to run the script? If you're trying to do it in code then you'll need to split it into two statements, perhaps using a regex to split on ^GO$
Try
IF OBJECT_ID ('idhere') IS NOT NULL
DROP PROCEDURE idhere
GO
CREATE PROCEDURE idhere
#paramsHere PARAMTYPE
AS
BEGIN
//...code here...
END
GO
This is how I do it, I'm not sure what version of SQL SERVER my work uses, I believe its 2005.
The easiest way I've found for executing a large scripts outside SSMS from a tool is to use the SQLCMD. (iSQL pre sql 2005) This will work with any environment that allows you to run a shell command.
From the MSDN article
The sqlcmd utility lets you enter
Transact-SQL statements, system
procedures, and script files at the
command prompt, in Query Editor in
SQLCMD mode, in a Windows script file
or in an operating system (Cmd.exe)
job step of a SQL Server Agent job.
This utility uses OLE DB to execute
Transact-SQL batches.
It would be better to use this syntax for the existence check:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[foo]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[foo]
GO
As written, if there was a foo sproc in any schema it would try to drop it. Not sure if that will make your problem go away though. If you use SSMS, there is an option to script a stored procedure as DROP and CREATE; that syntax should work.
Check Jon Galloway's post: Handling "GO" Separators in SQL Scripts - the easy way
It might have the answer you are seeking.

Resources