How to use declared variables in INNER SELECT Statement in Snowflake? - snowflake-cloud-data-platform

How to use SELECT Sub-Query in alias for a column?
Here's my script:-
/*Declaring variables:*/
SET period= '3';
SET smryseg=concat('sku',$period,'_smry');
SET spend= concat('sku',$period,'')
/*Printing it:*/
SELECT $period; /* #O/P: 3 */
SELECT $smryseg; /* #O/P: sku3_smry */
SELECT $spend; /* #O/P: sku3_spend */
/*now I want to use this variable in my INNER SELECT query:*/
create table IDENTIFIER ($smryseg) as
SELECT sum(spend) as (SELECT $spend)
FROM my_table;
Here, the last query is giving me an error, I also tried using IDENTIFIER, CONCAT, SUBSRING, $ ,removing parenthesis and much more.
I just want the name of column 'sum(spend)' obtained as 'sku3_spend' i.e in dynamic format

You can rename the column afterwards. Here's a self-contained example:
set spend_col='sku3_spend';
create or replace table t as select sum(spend) as x from values(1),(2),(3) s(spend);
alter table t rename column x to identifier($spend_col);
UPDATE
You can store dynamically named columns in an object:
set spend_col='sku3_spend';
create or replace table t as
select object_construct($spend_col, sum(spend)) data
from values(1),(2),(3) s(spend);
select data:sku3_spend from t;

Related

Regexp_Replace using joining a table in snowflake

I wanted to replace data in tableB with data in tableA.
Table A:
Source_Col
Target_Col
DB_DEV
DB_UAT
CDB_DEV
CDB_UAT
I have another table which has one col with the value "Create or replace DB_DEV.SCH.VIEW AS SELECT * FROM CBD_DEV.SCH.TABLENAME".
I wanted to replace DB_DEV with DB_UAT and CBD_DEV with CBD_UAT querying from TableA. Is that possible?
-- Revised to use tables:
-- Create the source and target string patterns to replace
create or replace table str_replace (source string, target string);
insert into str_replace values ('DB_DEV','DB_UAT'),('CDB_DEV', 'CDB_UAT');
-- Create the table containing the original strings to be modified
create or replace table orig_strings (query string, new_query string);
insert into orig_strings values ('Create or replace view DB_DEV.SCH.V_TABLEA AS SELECT * FROM CDB_DEV.SCH.TABLENAME;',null),('Create or replace view DB_DEV.SCH.V_TABLEB AS SELECT * FROM CDB_DEV.SCH.TABLENAME;',null);
--- Query with row_number partition to pick 1st row from Cartesian join
select
os.query,
regexp_replace(os.query, str.source, str.target) as new_query
from
orig_strings os,
str_replace str QUALIFY row_number() over (
partition by os.query
order by
os.query
) = 1;
-- Results
QUERY
NEW_QUERY
Create or replace view DB_DEV.SCH.V_TABLEA AS SELECT * FROM CDB_DEV.SCH.TABLENAME; Create or replace view DB_UAT.SCH.V_TABLEA AS SELECT * FROM CDB_UAT.SCH.TABLENAME;
Create or replace view DB_DEV.SCH.V_TABLEB AS SELECT * FROM CDB_DEV.SCH.TABLENAME; Create or replace view DB_UAT.SCH.V_TABLEB AS SELECT * FROM CDB_UAT.SCH.TABLENAME;
-- Update the table with the modified string
update orig_strings os
set os.new_query = regexp_replace(os.query,str.source,str.target)
from str_replace str;
select * from orig_strings;
-- Results:
QUERY NEW_QUERY
Create or replace view DB_DEV.SCH.V_TABLEA AS SELECT * FROM CDB_DEV.SCH.TABLENAME; Create or replace view DB_UAT.SCH.V_TABLEA AS SELECT * FROM CDB_UAT.SCH.TABLENAME;
Create or replace view DB_DEV.SCH.V_TABLEB AS SELECT * FROM CDB_DEV.SCH.TABLENAME; Create or replace view DB_UAT.SCH.V_TABLEB AS SELECT * FROM CDB_UAT.SCH.TABLENAME;

How to loop with different values in T-SQL query?

I have some specific set of values that I want to filter on a column, I don't want to do an 'in' clause in SQL Server. I want to use loop to pass in different set of values each time.
For example if there is a name column in my data, and I want to run query 5 times with different filter value.
Please look at the loop query attached below.
DECLARE #cnt INT = 1;
WHILE #cnt < 94
BEGIN
SELECT Name, COUNT(*) AS Number_of_Names
FROM Table
WHERE name IN ('John')
AND value IS NOT NULL
GROUP BY Name
SET #cnt = #cnt + 1;
END;
I want to pass in different values under 'name' column at each loop like john in the case above, then mary in the next loop likewise based on set of values I pass in the variable like #values = John,Mary,Nicole,matt etc..
Considering the comments on your question, this should give you an idea on how to achieve a solution without using loops and still get all the names even when the name is not present on the table.
SELECT Name,
COUNT(value) AS Number_of_Names --Only count when value is not null
FROM (VALUES('John'), ('Mary'), ('Nicole'), ('Matt'))Names(name) --This can be replaced by a table-valued parameter or temp table.
LEFT JOIN Table t ON Names.name = t.name
--WHERE name IN ('John') /*No longer needed*/
--AND value IS NOT NULL /*Removed this because it would make the OUTER JOIN behave as an INNER JOIN*/
GROUP BY Name;

How to use table variable in a NOT IN sql statement

I am trying to use the table variable #notified in a NOT IN where clause like this....
DECLARE #notified TABLE (DMT_ID INT)
INSERT INTO #notified
SELECT [DMT_ID]
FROM [dbo].[PU_Transaction]
WHERE [PU_TransactionStatus] = 3
SELECT * from #notified
SELECT [NRO_TRANSACCION]
FROM [dbo].[TRANSACCION]
WHERE [NRO_TRANSACCION] NOT in (#notified)
But I am getting this error in the last SELECT
Must declare the scalar variable "#notified".
What is wrong ? How can this be solved.
You need to use this:
SELECT [NRO_TRANSACCION]
FROM [dbo].[TRANSACCION]
WHERE [NRO_TRANSACCION] NOT IN (SELECT DMT_ID FROM #notified)
You need to put a SELECT statement in the NOT IN clause - not just a table variable name...
select x from y where x not in (select x from z)
You should have two selects to use a not in.

Copy records with dynamic column names

I have two tables with different columns in PostgreSQL 9.3:
CREATE TABLE person1(
NAME TEXT NOT NULL,
AGE INT NOT NULL
);
CREATE TABLE person2(
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL
);
INSERT INTO person2 (Name, Age, ADDRESS, SALARY)
VALUES ('Piotr', 20, 'London', 80);
I would like to copy records from person2 to person1, but column names can change in program, so I would like to select joint column names in program. So I create an array containing the intersection of column names. Next I use a function: insert into .... select, but I get an error, when I pass the array variable to the function by name. Like this:
select column_name into name1 from information_schema.columns where table_name = 'person1';
select column_name into name2 from information_schema.columns where table_name = 'person2';
select * into cols from ( select * from name1 intersect select * from name2) as tmp;
-- Create array with name of columns
select array (select column_name::text from cols) into cols2;
CREATE OR REPLACE FUNCTION f_insert_these_columns(VARIADIC _cols text[])
RETURNS void AS
$func$
BEGIN
EXECUTE (
SELECT 'INSERT INTO person1 SELECT '
|| string_agg(quote_ident(col), ', ')
|| ' FROM person2'
FROM unnest(_cols) col
);
END
$func$ LANGUAGE plpgsql;
select * from cols2;
array
------------
{name,age}
(1 row)
SELECT f_insert_these_columns(VARIADIC cols2);
ERROR: column "cols2" does not exist
What's wrong here?
You seem to assume that SELECT INTO in SQL would assign a variable. But that is not so.
It creates a new table and its use is discouraged in Postgres. Use the superior CREATE TABLE AS instead. Not least, because the meaning of SELECT INTO inside plpgsql is different:
Combine two tables into a new one so that select rows from the other one are ignored
Concerning SQL variables:
User defined variables in PostgreSQL
Hence you cannot call the function like this:
SELECT f_insert_these_columns(VARIADIC cols2);
This would work:
SELECT f_insert_these_columns(VARIADIC (TABLE cols2 LIMIT 1));
Or cleaner:
SELECT f_insert_these_columns(VARIADIC array) -- "array" being the unfortunate column name
FROM cols2
LIMIT 1;
About the short TABLE syntax:
Is there a shortcut for SELECT * FROM?
Better solution
To copy all rows with columns sharing the same name between two tables:
CREATE OR REPLACE FUNCTION f_copy_rows_with_shared_cols(
IN _tbl1 regclass
, IN _tbl2 regclass
, OUT rows int
, OUT columns text)
LANGUAGE plpgsql AS
$func$
BEGIN
SELECT INTO columns -- proper use of SELECT INTO!
string_agg(quote_ident(attname), ', ')
FROM (
SELECT attname
FROM pg_attribute
WHERE attrelid IN (_tbl1, _tbl2)
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0 -- no system columns
GROUP BY 1
HAVING count(*) = 2
) sub;
EXECUTE format('INSERT INTO %1$s(%2$s) SELECT %2$s FROM %3$s'
, _tbl1, columns, _tbl2);
GET DIAGNOSTICS rows = ROW_COUNT; -- return number of rows copied
END
$func$;
Call:
SELECT * FROM f_copy_rows_with_shared_cols('public.person2', 'public.person1');
Result:
rows | columns
-----+---------
3 | name, age
Major points
Note the proper use of SELECT INTO for assignment inside plpgsql.
Note the use of the data type regclass. This allows to use schema-qualified table names (optionally) and defends against SQL injection attempts:
Table name as a PostgreSQL function parameter
About GET DIAGNOSTICS:
Count rows affected by DELETE
About OUT parameters:
Returning from a function with OUT parameter
The manual about format().
Information schema vs. system catalogs.

How to select and assign multiple entries into a array like variable in sql?

I am new to sql. I want some thing like
DECLARE #VALID_ITEM_NUMBERS ITEM_NUMBER
SELECT #ITEM_NUMBERS = ITEM_NUMBER FROM [dbo].[ITEM] where IS_VALID = 1
(
here in the first line ITEM_NUMBER is a predefined type,
and on the second line ITEM_NUMBER refers to a column (of type ITEM_NUMBER) in the table named ITEM. IS_VALID is also a column in ITEM table
)
But SET or SELECT returns only one value. I want #VALID_ITEM_NUMBERS to contain all the valid item numbers, like an array.
Is there any way to do this without crating a separate stored procedure?
create one table variable to store all the values
declare #ITEM_NUMBERS table (ITEM_NUMBER int NOT NULL)
insert into #ITEM_NUMBERS(ITEM_NUMBER)
(select ITEM_NUMBER FROM [dbo].[ITEM] where IS_VALID = 1 )
select ITEM_NUMBER from #ITEM_NUMBERS

Resources