Snowflake bulk insert with select query in nodejs - binding

I'm trying to bulk insert into table with select statement and setting bind variable. I get bind variable not set error. But the same works if it is just insert with bind variables. When I'm using with select it is giving this error.
connection.execute({
sqlText: 'insert into table1(col1, col2, col3) select distinct col1, ?,? from table2 where col2=?',
binds: [[1,2,3],[4,5,6]]})

I get bind variable not set error.
The third bind variable is not set:
sqlText: '... select distinct col1, ?,? from table2 where col2=?'
| | |
1 2 3
So there are three bind placeholders, but only two array members in the bind:
binds: [[1,2,3],[4,5,6]]
---1--- ---2---
If you only need to pass two bind variables (two arrays), you can use the same bind variable more than once by referencing it like :1 and :2
sqlText: '... select distinct col1, :1,:2 from table2 where col2=:2'
The thing is, even if you supply a third bind variable I'm not sure it will work. Other external clients (JDBC, ODBC) cannot bind arrays. It may work in Node.js, but if not you can send the arrays as strings and use the split function on them in the SQL to split them into arrays.

Related

Is there any way to append the variable in big query select in stored procedure

I am trying to call the variable in a select query like below:
BEGIN
DECLARE TGT_LOAD_STATUS_TBL STRING;
SET TGT_LOAD_STATUS_TBL=''||PROJ_ID||'.'||TGT_SCHEMA||'.'||LOAD_STATUS_TBL||'';
FOR FETCH_TEST IN (select col1 from TGT_LOAD_STATUS_TBL WHERE LOAD_STATUS='N')
DO
INSERT INTO project.datasetid.table VALUES(FETCH_TEST.col1);
END FOR;
END
Is there any way to append the variable in a select query?
You can use build your SQL statement by concatenating some strings together and then execute it using EXECUTE IMMEDIATE. This is exactly the use case that EXECUTE IMMEDIATE exists for
I don't think it's a good practice to update a table one by one within a loop.
Instead consider a bulk update using a dynamic sql like below
EXECUTE IMMEDIATE FORMAT("""
INSERT INTO table1
SELECT col1 FROM `%s` WHERE LOAD_STATUS='N'
""", TGT_LOAD_STATUS_TBL);
Test Query:
DECLARE TGT_LOAD_STATUS_TBL DEFAULT 'table2';
CREATE TEMP TABLE table1 (col1 STRING);
CREATE TEMP TABLE table2 AS
SELECT 'a' col1, 'N' LOAD_STATUS UNION ALL
SELECT 'b', 'Y' UNION ALL
SELECT 'c', 'N' UNION ALL
SELECT 'd', 'N' UNION ALL
SELECT 'e', 'N' ;
EXECUTE IMMEDIATE FORMAT("""
INSERT INTO table1
SELECT col1 FROM `%s` WHERE LOAD_STATUS='N'
""", TGT_LOAD_STATUS_TBL);
SELECT * FROM table1;

Use parameter in UDF or Stored Procedure to return table

I have a case when using the Snowflake API. We have a bunch of materialized views, multiple for each customer of ours. When using the API, we would like to use functions or stored procedures to produce a result in runtime, and taking the customer ID as a parameter. This parameter would be used to fetch data from the correct views, to avoid have functions for each client. However, I'm running into some issues:
SQL UD(T)F isn't working, since it seems that you can't
use a parameter in the FROM clause. Neither can you use variables or
running multiple statements if I understood it correctly.
JavaScript UD(T)F isn't working since your not allowed to execute
statements.
Stored procedures are working for single values (which is one use
case), but not for returning a table. It can return a VARIANT, but
that would add work in the service consuming the API which we
would like to avoid.
Do you have any suggestions on how to to achieve the result we're after? We could create pre-calculated views with the results we're after, but that would result in a ton of views since we need other parameters as well in the API for a dynamic (filtered) result. Therefore a function-based approach seems much more neat and easier to maintain.
Thanks for your help and support!
If the view structure is the same for each client, you can do a UDTF with UNION ALL, merge all views and filter only for the one you need.
In practice, you will always read only one view depending on the parameter.
Something like that:
create function t(Client varchar)
returns table(col1 varchar, col2 varchar)
as
$$
SELECT col1, col2
FROM ViewClient1
WHERE Client = 'Client1'
UNION ALL
SELECT col1, col2
FROM ViewClient2
WHERE Client = 'Client2'
UNION ALL
SELECT col1, col2
FROM ViewClient3
WHERE Client = 'Client3'
$$;
Snowflake Scripting stored procedure could be used.
create or replace procedure test_sp_dynamic(table_name string)
returns table(col varchar, col2 varchar)
language sql
as
$$
declare
res RESULTSET;
query VARCHAR DEFAULT 'SELECT Y, Z FROM TABLE(?)';
begin
res := (execute immediate :query using (TABLE_NAME));
return table(res);
end;
$$;
Test data:
CREATE OR REPLACE TABLE view_1(Y VARCHAR, Z VARCHAR) AS SELECT 1, 2;
CREATE OR REPLACE TABLE view_2(Y VARCHAR, Z VARCHAR) AS SELECT 3, 4 ;
CALL test_sp_dynamic('VIEW_1');
-- 1 2
CALL test_sp_dynamic('VIEW_2');
-- 3 4

How to insert CDC Data from a stream to another table with dynamic column names

I have a Snowflake stored procedure and I want to use "insert into" without hard coding column names.
INSERT INTO MEMBERS_TARGET (ID, NAME)
SELECT ID, NAME
FROM MEMBERS_STREAM;
This is what I have and column names are hardcoded. The query should copy data from MEMBERS_STREAM to MEMBERS_TARGET. The stream has more columns such as
METADATA$ACTION | METADATA$ISUPDATE | METADATA$ROW_ID
which I am not intending to copy.
I don't know of a way to not copy the METADATA columns if not hardcoding. However if you don't want the data maybe the easiest thing to do is to add them to your target, INSERT using a SELECT * and later in the sp set them to NULL.
Alternatively, earlier in your sp, run an ALTER TABLE ADD COLUMN to add the columns, INSERT using SELECT * and then after that run an ALTER TABLE DROP COLUMN to remove the columns? That way your table structure stays the same, albeit briefly it will have some extra columns.
A SELECT * is not usually recommended but it's the easiest alternative I can think of

Distinct values from influxdb

When I run a distinct query on the influxdb, I get all results within one row. I need them all on different rows.
I've tried to select other fields however with distinct you can only select one field to query.
SELECT distinct("value_name") FROM "value_data"
name: value_data
time distinct
0 [TT_2028 TT_2090 TT_2216 TT_2217 TT_2237 TT_2238 TT_2239 TT_2240 TT_2241 TT_2243 TT_2248 TT_2249 TT_2250 TT_2251 TT_2252 TT_2253 james_test master testing_nightly_build test2]
I need the distinct values in new rows, not all on one row.
The docs show a distinct query with serrated rows
https://docs.influxdata.com/influxdb/v1.7/query_language/functions/#distinct
I think that you search for group by instead of distinct on string field.
Try something like this:
SELECT data1 FROM "value_data" GROUPBY value_name

Hive join query to list columns from only one table

I am writing a hive query to join two tables; table1 and table2. In the result I just need all columns from table1 and no columns from table2.
I know the solution where I can select all the columns manually by specifying table1.column1, table1.column2.. and so on in the select statement. But I have about 22 columns in table 1. Also, I have to do the same for multiple other tables ans its painful process.
I tried using "SELECT table1.*", but I get a parse exception.
Is there a better way to do it?
Hive 0.13 onwards the following query syntax works:
SELECT a.* FROM a JOIN b ON (a.id = b.id)
This query will select all columns from a. So instead of typing all the column names (making the query cumbersome), it is a better idea to use tablealias.*

Resources