where used list - Querying the Snowflake metadata information - snowflake-cloud-data-platform

Is there a way to query the metadata DDL to get the list of views using a table?
or list of views using another view etc?
i.e. where used list of a table or view across various schemas.
Thanks.

Unfortunately, there isn't. However, Snowflake offers GET_OBJECT_REFERENCES() that returns a list of objects that a specified view references. You can materialize the results of this function for all views and then do a reverse lookup for referring entities for a particular table/view.
https://docs.snowflake.net/manuals/sql-reference/functions/get_object_references.html

As Sahaj indicated in his answer, there is no direct way to select the names of all views using a table. You can create a stored procedure to fetch this information using GET_OBJECT_REFERENCES, however, with the caveat that it will be quite slow if you have a significant number of objects in your database:
-- Finds all references to the table with the provided name in the
-- active database. Returns them as a comma-separated list.
CREATE OR REPLACE PROCEDURE GetTableReferences(DATABASE_NAME VARCHAR, SCHEMA_NAME VARCHAR, TABLE_NAME VARCHAR)
RETURNS VARCHAR LANGUAGE JAVASCRIPT AS $$
var query = "SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_CATALOG = '" + DATABASE_NAME + "'";
var statement = snowflake.createStatement( {sqlText: query} );
var result_set = statement.execute();
var matches = '';
while (result_set.next()) {
var schema = result_set.getColumnValue(1);
var table = result_set.getColumnValue(2);
var object_references_query =
"SELECT 1 FROM TABLE(GET_OBJECT_REFERENCES(DATABASE_NAME => '" + DATABASE_NAME
+ "', SCHEMA_NAME => '" + schema + "', OBJECT_NAME => '" + table + "')) WHERE REFERENCED_SCHEMA_NAME = '"
+ SCHEMA_NAME + "' AND REFERENCED_OBJECT_NAME = '" + TABLE_NAME + "'";
var object_references_statement = snowflake.createStatement( {sqlText: object_references_query} );
try {
if (object_references_statement.execute().next()) {
// This is a match
if (matches.length !== 0) {
matches += ",";
}
matches += schema + "." + table;
}
} catch (err) {
// Ignore invalid views.
}
}
return matches;
$$;
CALL GetTableReferences('MY_DATABASE_NAME', 'MY_SCHEMA_NAME', 'MY_TABLE_NAME');

Related

How to escape comma character in a javascript procedure in wherescape, snowflake?

I have a table with 2 columns:
Tablename
Fieldname
tbl
name
tbl
LastName
I need to display one row, having Fieldname values concatenated:
tbl --> name, lastName
So, I am using Listagg fct to concatenate the values :
listagg (fieldname,',') as newCol.
Running this command in Snowflake, works fine and displays want i need.
But, because we are using Wherescape to create procedures, adding this function in a javascript procedure, fails, because of COMMA separator used in listagg fct.
I tried with different escape characters, but nothing worked. (/,,/[])..
If I change the character in &,* it works, but I have to use comma.
Creating the newCol with listagg with & instead of ",", works and if I use a replace fct to change it to ",", it fails again :(
What should I use to have COMMA between the values for the newCol.
It is mandatory to have COMMA, because the column will be used in an update statement.
EDIT:
CREATE OR REPLACE PROCEDURE sp_myprocedure_test()
RETURNS VARCHAR(16777216)
language javascript
execute as CALLER
as
$$
const generateUpdStmt = ` SELECT 'UPDATE tbl SET ' || c.col_update AS STMT_SQL
,c.col_update
FROM (
select TABLE_NAME
, listagg (concat(field_name, ' = ''#tst''' ), ' , ') within group (order by TABLE_NAME, field_name asc) as col_update
from tbl
group by TABLE_NAME
) c
;`;
try {
var return_value = "Init: ";
var stmt_update = snowflake.createStatement({sqlText: generateUpdStmt});
var result_stmt = stmt_update.execute();
while (result_stmt.next())
{
var result_stmt_value_2 = result_stmt.getColumnValue(2);
return_value += result_stmt_value_2 + "\n";
}
result = " Status: Succeeded. \n";
}
catch (err) {
result = "Failed: Code:" + err.code + "\n State: " + err.state;
result += "\n Message: " + err.message;
result += "\nStack Trace:\n" + err.stackTraceTxt;
return result;
}
return return_value;
$$
EDIT 2:
Returning result in wherescape with "&" instead of "," delimiter:
enter image description here
Returning result in wherescape with "," delimiter:
enter image description here
I created a minimal tbl table and when I run this:
SELECT 'UPDATE tbl SET ' || c.col_update AS STMT_SQL
,c.col_update
FROM (
select TABLE_NAME
, listagg (concat(field_name, ' = ''#tst''' ), ' , ') within group (order by TABLE_NAME, field_name asc) as col_update
from tbl
group by TABLE_NAME
) c ;
I get the following result:
+--------------------------------------------------+-----------------------------------+
| STMT_SQL | COL_UPDATE |
+--------------------------------------------------+-----------------------------------+
| UPDATE tbl SET LastName = '#tst' , name = '#tst' | LastName = '#tst' , name = '#tst' |
+--------------------------------------------------+-----------------------------------+
I see your JS returns the same values. I edited it to return both columns as one string:
CREATE OR REPLACE PROCEDURE sp_myprocedure_test()
RETURNS VARCHAR(16777216)
language javascript
execute as CALLER
as
$$
const generateUpdStmt = ` SELECT 'UPDATE tbl SET ' || c.col_update AS STMT_SQL
,c.col_update
FROM (
select TABLE_NAME
, listagg (concat(field_name, ' = ''#tst''' ), ' , ') within group (order by TABLE_NAME, field_name asc) as col_update
from tbl
group by TABLE_NAME
) c
;`;
try {
var return_value = "";
var stmt_update = snowflake.createStatement({sqlText: generateUpdStmt});
var result_stmt = stmt_update.execute();
while (result_stmt.next())
{
return_value += result_stmt.getColumnValue(1) + " | " + result_stmt.getColumnValue(2);
}
}
catch (err) {
result = "Failed: Code:" + err.code + "\n State: " + err.state;
result += "\n Message: " + err.message;
result += "\nStack Trace:\n" + err.stackTraceTxt;
return result;
}
return return_value;
$$
call sp_myprocedure_test();
+--------------------------------------------------------------------------------------+
| SP_MYPROCEDURE_TEST |
+--------------------------------------------------------------------------------------+
| UPDATE tbl SET LastName = '#tst' , name = '#tst' | LastName = '#tst' , name = '#tst' |
+--------------------------------------------------------------------------------------+
Can you tell me what is expected?

SnowFlake StoredProcedure Code not working when creating dynamic statement for information_schema.columns

I am new to Snowflake, trying to create a small sp to get the row and col count of any table
SP Name :
"GET_ROW_COUNT_TESTSP"("DATABASE_NAME" VARCHAR(16777216), "SCHEMA_NAME" VARCHAR(16777216), "TABLE_NAME" VARCHAR(16777216))
Snippets from body :
var sql_command_columncount = "select COUNT (DISTINCT COLUMN_NAME) AS COLCOUNT from "+DATABASE_NAME+"."+"information_schema.columns where TABLE_CATALOG ="+''+DATABASE_NAME+''+ " and table_schema = " + ''+SCHEMA_NAME+''+ "and table_name = " + '' +TABLE_NAME+ ''+ "and column_name <> ''TESTCOLUMNNAME'' ";
var stmt2 = snowflake.createStatement(
{
sqlText: sql_command_columncount
}
);
var res2 = stmt2.execute();
res2.next();
COLCOUNT = res2.getColumnValue(1);
return COLCOUNT;
This is throwing error, tried all different single quote, not working, hard-coding of dbname,schemaname,tablename is working.
Any help is appreciated.
There is a problem with quote encapsulation on that line. The best way to address this is to use backticks to enclose your SQL string. This will allow use of single and double quotes and line breaks without having to concatenate strings. It will also allow use of template literals, which means for any variable X you can replace its literal value in a string using the syntax ${X}. Your SQL statement would look something like this:
var sql_command_columncount =
`select COUNT (DISTINCT COLUMN_NAME) AS COLCOUNT
from ${DATABASE_NAME}.information_schema.columns
where TABLE_CATALOG = '${DATABASE_NAME}
and table_schema = '${SCHEMA_NAME}'
and table_name = ${TABLE_NAME}
and column_name <> 'TESTCOLUMNNAME'
`;
I agree with the above answer, there were a few missing quotes above so corrected it and below is the working code as tested.
CREATE OR REPLACE PROCEDURE "GET_ROW_COUNT_TESTSP"("DATABASE_NAME"
VARCHAR(16777216), "SCHEMA_NAME" VARCHAR(16777216), "TABLE_NAME"
VARCHAR(16777216))
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
EXECUTE AS OWNER
AS
$$
var sql_command_columncount = `select COUNT (DISTINCT COLUMN_NAME)
AS COLCOUNT from ${DATABASE_NAME}.information_schema.columns where
TABLE_CATALOG = '${DATABASE_NAME}' and table_schema =
'${SCHEMA_NAME}'
and table_name = '${TABLE_NAME}' and column_name <>
'TESTCOLUMNNAME'
`
var stmt2 = snowflake.createStatement(
{
sqlText: sql_command_columncount
}
);
var res2 = stmt2.execute();
res2.next();
COLCOUNT = res2.getColumnValue(1);
return COLCOUNT;
$$;
Cleaner version without using ticks and used double quote and parameterized ...
create or replace procedure getrowcounts_1(DATABASE_NAME VARCHAR, SCHEMA_NAME VARCHAR, TABLE_NAME VARCHAR)
RETURNS VARCHAR LANGUAGE JAVASCRIPT AS $$
var sql_command="Select row_count from "+DATABASE_NAME +"."+SCHEMA_NAME + "."+ "TABLES WHERE TABLE_NAME="+"'"+TABLE_NAME+"'";
var stmt = snowflake.createStatement(
{
sqlText: sql_command
}
);
var res = stmt.execute();
res.next();
COLCOUNT = res.getColumnValue(1);
return COLCOUNT;
$$;
Output:

Drop multiple tables at once

In SQL you have the ability to drop multiple tables at once with a simple query like:
drop table a, b, c
In Snowflake this doesnt work. Is there a way to drop multiple tables at once?
Maybe you can create a simple SP to do this for you:
create or replace procedure drop_tables(list varchar)
returns string
language javascript
as
$$
var l = LIST.split(',');
var sqls = [];
for (i=0; i<l.length; i++) {
var sql = "DROP TABLE IF EXISTS " + l[i].trim();
var rs = snowflake.execute( {sqlText: sql});
sqls.push(sql);
}
return JSON.stringify(sqls);
$$;
call drop_tables('mytest,test , my_table ');
+---------------------------------------------------------------------------------------------+
| DROP_TABLES |
|---------------------------------------------------------------------------------------------|
| ["DROP TABLE IF EXISTS mytest","DROP TABLE IF EXISTS test","DROP TABLE IF EXISTS my_table"] |
+---------------------------------------------------------------------------------------------+
Hi you can do a 2 step like this where you generate the DDL if you have the list of tables to be deleted.
SELECT 'DROP TABLE ' || table_name || ';'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE IN ('TAB1', 'TAB2');

Retrieve data from multiple tables from sqlite database titanium

I was trying to retrieve data from multiple tables from sqlite database with titanium using select statement with left join property.
It retrieves null or undefined and I used this statement with sqlite administrator, it retrieves data.
You can check my code:
var db = Ti.Database.install('Path/DB_Name.s3db', 'DB_Name');
var rows = db.execute(
'select c.CustomerID,c.Name, c.CustomerCode,v.ConfirmationDate from Customer as c' +
' left join Visits as v on c.CustomerID==v.CustomerID ' +
' order by v.ConfirmationDate desc');
Try it like this:
var db = Ti.Database.install('Path/DB_Name.s3db', 'DB_Name');
var rows = db.execute(
'select c.CustomerID,c.Name, c.CustomerCode,v.ConfirmationDate from Customer as c' +
' left join Visits as v on c.CustomerID=v.CustomerID ' +
' order by v.ConfirmationDate desc');
Single "="

how to use more than one string in like expression in sql

I have a list of 20 (or more) words (string) and want to select the rows that have these word in 3 of their column. I should use like expression of sql. but I don't know how to use more than one string in like expression.
(I do it with union now, but I have at least 60 select statement and think it reduced the performance, Is it really reduce the performance?)
//get the advertise that have similar keywords
foreach (string str in keywords)
{
if (str != "")
{
if (!string.IsNullOrEmpty(sqlQuery)) sqlQuery += " union";
sqlQuery = "select * from AD_Advertise where (AdKeyWords like N'%" + str + "%'"
+ " OR AdTitle like N'%" + str + "%' "
+ " OR AdDescription like N'%" + str + "%' "
+ " OR AdGroupItemCode=" + adinfo.AdGroupItemCode + ")"
+ " AND AdSiteID=" + CMSContext.CurrentSiteID
+ " AND AdShow='True' "
+ " AND ItemID != " + ADId;
}
}
ds = cn.ExecuteQuery(sqlQuery,null);//("AD.Advertise.selectall", null, where, "ItemModifiedWhen");
Answer:
At last I used below code:
if object_id('tempdb..#WordList') is not null
drop table #WordList
CREATE TABLE #WordList ( KeyWord nvarchar(100))
insert into #WordList values (N'حقوقی'),(N'وکیل');
SELECT DISTINCT *
FROM AD_ADvertise a
LEFT JOIN #WordList k
ON a.AdKeywords LIKE '%' + k.KeyWord + '%'
OR a.AdTitle LIKE '%' + k.KeyWord + '%'
OR a.AdDescription LIKE '%' + k.KeyWord + '%'
WHERE
(k.KeyWord IS NOT NULL OR a.AdGroupItemCode = #AdGroupItemCode)
AND a.AdSiteId = #AdSiteId
AND a.AdShow = 'True'
AND a.ItemId != #ItemId
;drop table #WordList
Create a stored procedure with a table valued parameter that takes your list of strings.
Have a join between the table valued parameter and your tables AD_Advertise on the like.
Heres how to do the Table type + the stored procedure:
CREATE TYPE WordList AS TABLE (Word NVARCHAR(50));
GO
CREATE PROCEDURE GetAddsMatchingKeywords
#KeywordList WordList READONLY,
#AdGroupItemCode VARCHAR(50),
#AdSiteId INT,
#ItemId INT
AS
SELECT DISTINCT
a.AdTitle,
a.ItemId -- extend to the full column list
FROM AD_ADvertise a
LEFT JOIN #KeywordList k ON a.AdKeywords LIKE '%' + k.Word + '%' OR a.AdTitle LIKE '%' + k.Word + '%' OR a.AdDescription LIKE '%' + k.Word + '%'
WHERE
(k.Word IS NOT NULL OR a.AdGroupItemCode = #AdGroupItemCode)
AND a.AdSiteId = #AdSiteId
AND a.AdShow = 'True'
AND a.ItemId = #ItemId
GO
edit - misread the original question - thought you wanted to match 3 or more words.
This version matches any that have a single word in any of the 3 columns - like you wanted I think.
Don't ever build up a SQL string like that. Read about SQL injection before you go any further.
Ideally, you would have a table of keywords, rather than a string, and a join table to link between the item and the keywords.
If you persist in doing it this way, have a look at Full Text Search
//get the advertise that have similar keywords
foreach (string str in keywords)
{
if (str != "")
{
if (!string.IsNullOrEmpty(sqlQuery)) sqlQuery += " union";
sqlQuery = "select * from AD_Advertise where (AdKeyWords + AdTitle + AdDescription like N'%" + str + "%'"
+ " OR AdGroupItemCode=" + adinfo.AdGroupItemCode + ")"
+ " AND AdSiteID=" + CMSContext.CurrentSiteID
+ " AND AdShow='True' "
+ " AND ItemID != " + ADId;
}
}
ds = cn.ExecuteQuery(sqlQuery,null);//("AD.Advertise.selectall", null, where, "ItemModifiedWhen");

Resources