1

I have the below Snowflake Javascript Stored procedure where I need to replace multiple instances of a string in an sql statement.

 CREATE OR REPLACE PROCEDURE MYSCHEMA.CountryDelete(COUNTRY VARCHAR) 
    RETURNS string
    LANGUAGE JAVASCRIPT
    AS
    $$
        var error_msg = 'Success';      
        try 
        {
            var sql_cmd_temp = `DELETE FROM MYSCHEMA.CountryTable_{country} 
            WHERE COUNTRY_CODE = '{country}';`  
            var sql_cmd = sql_cmd_temp.replace("{country}", COUNTRY);       
            return sql_cmd;   
        }
        catch(err) 
        {
            error_msg += "ERROR : " + err.message;
        }
        return sql_cmd;     
    $$;

When I execute the above Stored procedure am getting the below output. Here, 1st instance of the {country} is getting replaced with CH (where CH is the parameter value that I am sending while executing this Stored procedure) but not the 2nd one.

DELETE FROM ODP_SUBNATIONAL_STAGING.IDP_SUBNATIONAL_SALES_CH 
        WHERE COUNTRY_CODE = '{country}';

I am expecting the below output.

DELETE FROM ODP_SUBNATIONAL_STAGING.IDP_SUBNATIONAL_SALES_CH 
            WHERE COUNTRY_CODE = 'CH';

I also tried Javascript's replaceAll instead of replace but it is returning [NULL].

Please note that since I have to hardcode the sql in multiple lines, I need to use the Grave accent symbol while storing sql string into the variable. Otherwise I would have used the " symbol to store the sql and use + symbol to make it dynamic.

It will be really thankful if someone can help in sorting this issue out.

3 Answers 3

0

Finally, I found a solution for this using the constructor function of the RegExp object.

var sql_cmd = sql_cmd_temp.replace(new RegExp('{country}', 'g'), COUNTRY);

Here's is the updated code.

CREATE OR REPLACE PROCEDURE MYSCHEMA.CountryDelete(COUNTRY VARCHAR) 
    RETURNS string
    LANGUAGE JAVASCRIPT
    AS
    $$
        var error_msg = 'Success';      
        try 
        {
            var sql_cmd_temp = `DELETE FROM MYSCHEMA.CountryTable_{country} 
            WHERE COUNTRY_CODE = '{country}';`  
            var sql_cmd = sql_cmd_temp.replace(new RegExp('{country}', 'g'), COUNTRY);       
            return sql_cmd;   
        }
        catch(err) 
        {
            error_msg += "ERROR : " + err.message;
        }
        return sql_cmd;     
    $$;

And here's the result.

DELETE FROM ODP_SUBNATIONAL_STAGING.IDP_SUBNATIONAL_SALES_CH 
            WHERE COUNTRY_CODE = 'CH';
Sign up to request clarification or add additional context in comments.

Comments

0

You can use JavaScript template literals ${myVariable}; then you don't have to do a replace on each variable used as a template in a string. This works as long as you terminate your string literal with backticks.

CREATE OR REPLACE PROCEDURE CountryDelete(COUNTRY VARCHAR) 
    RETURNS string
    LANGUAGE JAVASCRIPT
    AS
    $$
        var error_msg = 'Success';      
        try 
        {
            var sql_cmd = `DELETE FROM MYSCHEMA.CountryTable_${COUNTRY} 
            WHERE COUNTRY_CODE = '${COUNTRY}';`      
            return sql_cmd;   
        }
        catch(err) 
        {
            error_msg += "ERROR : " + err.message;
        }
        return sql_cmd;     
    $$;

1 Comment

While I compile this script (in DBVewer), it is asking for bind variable. I am also not able to override the country while I call this stored procedure. Is this how it work?
0

A safer way would be to use binds - if your plan is to execute the query within the stored procedure:


create or replace temp table prefix_delete_me as 
select 1 x, 'me' as country;

CREATE OR REPLACE PROCEDURE testbind(COUNTRY VARCHAR) 
RETURNS string
LANGUAGE JAVASCRIPT
AS
$$

var stmt = snowflake.createStatement({
    sqlText: `
        select *
        from identifier(:2)
        where country=:1
        and country != concat('hello', :1, :1)
    `
   , binds:[COUNTRY, 'prefix_delete_'+COUNTRY]
});

// execute the statement to prove its correct
stmt.execute(); 

// just get the sql statement
return stmt.getSqlText();
$$;
    
call testbind('me')

2 Comments

This looks to be the better solution than my answer. BTW, is there any way that I can use CountryTable_:1 rather than using identifier(:2)? Because in the real scenario my sql will be very big and that I will have variety of table names inside the sql.
I tried different ways of encoding the table names, but this is the best I got for now

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.