Snowflake task gives me no error but table is empty - sql

I have the following TASK in Snowflake:
CREATE OR REPLACE TASK TSK_MASTER
WAREHOUSE = MYWH
SCHEDULE = '1 MINUTE'
WHEN
SYSTEM$STREAM_HAS_DATA('MYSTREAM')
AS
INSERT INTO USER_DATA(ID,CREATED_AT,DEACTIVATED,EMAIL_ADDRESS,NAME,ROLE)
SELECT
vm.VALUE:id::string AS "ID",
vm.VALUE:created_at::timestamp AS "CREATED_AT",
vm.VALUE['profile']:deactivated::boolean AS "DEACTIVATED",
vm.VALUE['profile']:email_address::string AS "EMAIL_ADDRESS",
vm.VALUE['profile']:name::string AS "NAME",
vm.VALUE:role::string AS "ROLE"
FROM
MYSTREAM
, lateral flatten(input => RAW_JSON) vm
WHERE
vm.VALUE:entity_type::string = 'member'
AND
METADATA$ACTION = 'INSERT';
SELECT SYSTEM$STREAM_HAS_DATA('MYSTREAM') is TRUE but my task doesn't seem to run.
I then troubleshoot the following and get the IDs as intended.
SELECT
vm.VALUE:id::string AS "ID"
FROM
MYSTREAM
, lateral flatten(input => RAW_JSON) vm
WHERE
vm.VALUE:entity_type::string = 'member'
AND
SYSTEM$STREAM_HAS_DATA('MYSTREAM')
AND
METADATA$ACTION = 'INSERT';

All you need to do is ALTER TASK <TASK_NAME> RESUME

Related

How to make multiple SELECT queries at once in PostgreSQL?

Update: See the "Update" section below for the latest.
I have been working with Knex.js to build SQL queries in Node.js, and have the following code. This code works on a sort of graph data model (nodes and links), where there is a links table which has everything (links link to links). Given this code, I am wondering how I can make it one query instead of one query per attribute which is how it is now. The getTableName() function returns a string_links table for string values, and <x>_links tables for the other datatypes, while the "basic" links table is just called links.
Essentially how this works is, first query the top level where the parent_id is equal to some "type" ID, say we are querying "user" objects, the type would be "user". So let instance = ... is getting all the instance links from this user type. Then we go through each field of a query (a query for now is just boolean-valued map, like { email: true, name: true }). For each field of the query, we make a query to find all those nodes, linked off the instance, as so-called property links.
There are two types of properties, but don't need to go into too much detail on that. Essentially there are complex properties with audit trails and simple properties without audit trails. That is what is meant by the interactive branch in the logic.
How can I make this into one SQL query? The SQL query it prints out for an example is like this:
select "id" from "links" where "parent_id" = '47c1956bz31330c' and "name" = 'link' limit 1
select "value" from "string_links" where "parent_id" = (select "value" from "links" where "parent_id" = '47c1956bz31330cv' and "name" = 'name' limit 1) and "name" = 'value' limit 1
select "value" from "text_links" where "parent_id" = (select "value" from "links" where "parent_id" = '47c1956bz31330cv' and "name" = 'website' limit 1) and "name" = 'value' limit 1
select "value" from "integer_links" where "parent_id" = (select "value" from "links" where "parent_id" = '47c1956bz31330cv' and "name" = 'revenue' limit 1) and "name" = 'value' limit 1
select "value" from "boolean_links" where "parent_id" = '47c1956bz31330' and "name" = 'verified' limit 1
The original Node.js for Knex.js is here, but really I'm just concerned with how to write this as one regular SQL query, and I can figure out how to make it in Knex.js from there:
async function selectInteractiveInstance(user, name, query) {
const type = model.types[name]
const typeId = await baseSchemaController.selectType(name)
let instance = await knex.from(`links`)
.select('id')
.where('parent_id', typeId)
.where('name', 'instance')
.first()
// { id: 123, props: { ... } }
instance.props = {}
for (let field in query) {
let data = query[field]
let attrSchema = type[field]
const tableName = baseSchemaController.getTableName(attrSchema.type)
if (attrSchema.interactive) {
const query1 = knex
.from(`links`)
.select('value')
.where('parent_id', instance.link)
.where('name', field)
.first()
const record = await knex
.from(tableName)
.select('value')
.where('home', query1)
.where('name', 'value')
.first()
if (record) {
instance.props[field] = record.value
}
} else {
const record = await knex
.from(tableName)
.select('value')
.where('parent_id', instance.id)
.where('name', field)
.first()
if (record) {
instance.props[field] = record.value
}
}
}
return instance
}
The reason for asking is because the number of queries of this function is equal to the number of properties on the object, and I would like to avoid that, but not really that great at SQL yet. I don't see a straightforward or clear path on how to make this into one query, or know if it's possible.
It's also an issue for the following reason. If I want to grab 100 links, and their "fields" (in the primitive link tables), such that the primitive link values match a certain value, then you need to query all field tables simultaneously to see if the query can be satisfied.
Update
I finally landed on a query that works in the optimistic case:
select
"x"."id" as "id",
"s1"."value" as "name",
"s2"."value" as "inc_id",
"s3"."value" as "website",
"s4"."value" as "revenue",
"s5"."value" as "verified"
from "links" as "x"
inner join "links" as "c1" on "c1"."parent_id" = "x"."id"
inner join "string_links" as "s1" on "s1"."parent_id" = "c1"."value"
inner join "links" as "c2" on "c2"."parent_id" = "x"."id"
inner join "string_links" as "s2" on "s2"."parent_id" = "c2"."value"
inner join "links" as "c3" on "c3"."parent_id" = "x"."id"
inner join "text_links" as "s3" on "s3"."parent_id" = "c3"."value"
inner join "links" as "c4" on "c4"."parent_id" = "x"."id"
inner join "integer_links" as "s4" on "s4"."parent_id" = "c4"."value"
inner join "boolean_links" as "s5" on "s5"."parent_id" = "x"."id"
where "x"."parent_id" = '47c1956bz31330'
and "x"."name" = 'link'
and "c1"."name" = 'name'
and "s1"."name" = 'value'
and "c2"."name" = 'inc_id'
and "s2"."name" = 'value'
and "c3"."name" = 'website'
and "s3"."name" = 'value'
and "c4"."name" = 'revenue'
and "s4"."name" = 'value'
and "s5"."name" = 'verified'
This returns an object similar to what I am looking for, joining the same table several times, along with the primitive tables.
However, if any of the values are not linked (are socalled "null" in this context), then the inner join will fail and it will return nothing. How can I still have it return a subset of the object properties, whatever it can find? Is there anything like optional inner joins or anything like that?
Use LEFT JOIN and move possibly unsatisfied predicates to ON clause. Kind of
select
"x"."id" as "id",
"s1"."value" as "name",
"s2"."value" as "inc_id",
"s3"."value" as "website",
"s4"."value" as "revenue",
"s5"."value" as "verified"
from "links" as "x"
left join "links" as "c1" on "c1"."parent_id" = "x"."id" and "c1"."name" = 'name'
left join "string_links" as "s1" on "s1"."parent_id" = "c1"."value" and "s1"."name" = 'value'
left join "links" as "c2" on "c2"."parent_id" = "x"."id" and "c2"."name" = 'inc_id'
left join "string_links" as "s2" on "s2"."parent_id" = "c2"."value" and "s2"."name" = 'value'
left join "links" as "c3" on "c3"."parent_id" = "x"."id" and "c3"."name" = 'website'
left join "text_links" as "s3" on "s3"."parent_id" = "c3"."value" and "s3"."name" = 'value'
left join "links" as "c4" on "c4"."parent_id" = "x"."id" and "c4"."name" = 'revenue'
left join "integer_links" as "s4" on "s4"."parent_id" = "c4"."value" and "s4"."name" = 'value'
left join "boolean_links" as "s5" on "s5"."parent_id" = "x"."id" and "s5"."name" = 'verified'
where "x"."parent_id" = '47c1956bz31330'
and "x"."name" = 'link'

How to combine two SQL queries with dynamic table name into one in PostgreSQL

I have this SQL function which I'm trying to figure out how to make into one query:
async function verifyInteractiveInstanceAttributeIsUnique(typeId, key, val, attrSchema) {
const tableName = getTableName(attrSchema.type)
const instances = await knex.from(`links`)
.select('id')
.where('parent_id', typeId)
.where('name', 'instance')
const instanceIds = instances.map(x => x.id)
const existingRecord = await knex.from(tableName)
.whereIn('parent_id', instanceIds)
.where('name', key)
.first()
return !existingRecord
}
Essentially I think this is the SQL:
SELECT id FROM links
WHERE parent_id = ${typeId}
AND name = 'instance'
# store in IDS array lets say
SELECT * FROM ${tableName}
WHERE parent_id IN (IDS)
AND name = ${key}
LIMIT 1
How can I write this in plain SQL to do the query in one call?
Based on your sample SQL, you can use a subquery:
SELECT t.*
FROM ${tableName} t
WHERE t.parent_id IN (SELECT l.id
FROM links l
WHERE l.parent_id = ${typeId} AND
lname = 'instance'
) AND
t.l.name = ${key}
LIMIT 1

subrequest in case return error on clickhouse

So i try a make a view , actually this is my code :
drop table if exists computed_datum_hours_base;
create view computed_datum_hours_base
as select
toStartOfHour(datetime_value) as datetime_desc,
computed_id,
computed_kind,
computed_type,
case
when computed_type = 'intensive' then avg(value)
when computed_type = 'extensive.some' then sum(value)
when computed_type = 'extensive.differential' then
(
select value as value_f from ref_computed_datum
where ref_computed_id = computed_id
and ref_computed_kind = computed_kind
and ref_computed_type = computed_type
and ref_datetime_value = toStartOfHour(addHours(datetime_value, 1))
) - (
select value as value_f from ref_computed_datum
where ref_computed_id = computed_id
and ref_computed_kind = computed_kind
and ref_computed_type = computed_type
and ref_datetime_value = toStartOfHour(datetime_value)
)
end as value,
count(uuid) as nb_value
from computed_datum
join ref_computed_datum
on computed_id = ref_computed_id
and computed_kind = ref_computed_kind
and computed_type = ref_computed_type
where uuid = ref_uuid
group by
computed_id,
computed_kind,
computed_type,
toStartOfHour(datetime_value)
;
my issue is on the case for extensive.differential ...
clickhouse say he can found the column for computed_id ... like the subrequest is scoped and didn't have access to the colum from the main requeste ...
So this is another bug of clickhouse ?
Or there are a reel scope and i can't do this like this ...
( so How can do this ? )
Edit: full error
Code: 47, e.displayText() = DB::Exception: Missing columns: 'datetime_value' 'computed_kind' 'computed_type' 'computed_id' 'value' while processing query: 'SELECT value AS value_f FROM api_client.ref_computed_datum WHERE (ref_computed_id = computed_id) AND (ref_computed_kind = computed_kind) AND (ref_computed_type = computed_type) AND (ref_datetime_value = toStartOfHour(addHours(datetime_value, 1)))', required columns: 'value' 'computed_id' 'ref_computed_id' 'ref_computed_kind' 'computed_type' 'ref_computed_type' 'computed_kind' 'ref_datetime_value' 'datetime_value', source columns: 'ref_flags' 'ref_computed_kind' 'ref_computed_id' 'ref_datetime_value' 'ref_computed_type' 'ref_EventDateTime' 'ref_insert' 'ref_value' 'ref_uuid' (version 20.4.2.9 (official build))
computed_datum folow this structure :
EventDateTime DateTime default now(),
insert String,
uuid String default generateUUIDv4(),
datetime_value DateTime,
computed_id Int32,
computed_kind String,
computed_type String,
value Float64,
flags String
```
I make a ref view that only prefix all colum with ref_ for making a walkaround about the alias bug.
At this time clickhouse didn't support correlated query ...
cf: https://github.com/ClickHouse/ClickHouse/issues/6697

perl - update from two databases

i have two databases in mariadb and i want to update two databases,
#Connect to the database1.
my $db1 = DBI->connect("DBI:mysql:database=db1;host=ip",
"login", 'paswword',
{'RaiseError' => 1});
#Connect to the database2.
my $db2 = DBI->connect("DBI:mysql:database=db2;host=ip",
"login", 'password',
{'RaiseError' => 1});
this query not work
my $query3 = $db1->prepare("
UPDATE worldmap.worldmap_table t1
SET t1.severity = 1000
WHERE t1.host IN
(SELECT h.name
FROM host_inventory as i, hosts as h WHERE i.hostid=h.hostid and h.available=1)");
$query3->execute;
thanks for your response
Use a single connection. Reference tables using the db.table syntax.

Update multiple rows in same query using PostgreSQL

I'm looking to update multiple rows in PostgreSQL in one statement. Is there a way to do something like the following?
UPDATE table
SET
column_a = 1 where column_b = '123',
column_a = 2 where column_b = '345'
You can also use update ... from syntax and use a mapping table. If you want to update more than one column, it's much more generalizable:
update test as t set
column_a = c.column_a
from (values
('123', 1),
('345', 2)
) as c(column_b, column_a)
where c.column_b = t.column_b;
You can add as many columns as you like:
update test as t set
column_a = c.column_a,
column_c = c.column_c
from (values
('123', 1, '---'),
('345', 2, '+++')
) as c(column_b, column_a, column_c)
where c.column_b = t.column_b;
sql fiddle demo
Based on the solution of #Roman, you can set multiple values:
update users as u set -- postgres FTW
email = u2.email,
first_name = u2.first_name,
last_name = u2.last_name
from (values
(1, 'hollis#weimann.biz', 'Hollis', 'Connell'),
(2, 'robert#duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;
Yes, you can:
UPDATE foobar SET column_a = CASE
WHEN column_b = '123' THEN 1
WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')
And working proof: http://sqlfiddle.com/#!2/97c7ea/1
For updating multiple rows in a single query, you can try this
UPDATE table_name
SET
column_1 = CASE WHEN any_column = value and any_column = value THEN column_1_value end,
column_2 = CASE WHEN any_column = value and any_column = value THEN column_2_value end,
column_3 = CASE WHEN any_column = value and any_column = value THEN column_3_value end,
.
.
.
column_n = CASE WHEN any_column = value and any_column = value THEN column_n_value end
if you don't need additional condition then remove and part of this query
Let's say you have an array of IDs and equivalent array of statuses - here is an example how to do this with a static SQL (a sql query that doesn't change due to different values) of the arrays :
drop table if exists results_dummy;
create table results_dummy (id int, status text, created_at timestamp default now(), updated_at timestamp default now());
-- populate table with dummy rows
insert into results_dummy
(id, status)
select unnest(array[1,2,3,4,5]::int[]) as id, unnest(array['a','b','c','d','e']::text[]) as status;
select * from results_dummy;
-- THE update of multiple rows with/by different values
update results_dummy as rd
set status=new.status, updated_at=now()
from (select unnest(array[1,2,5]::int[]) as id,unnest(array['a`','b`','e`']::text[]) as status) as new
where rd.id=new.id;
select * from results_dummy;
-- in code using **IDs** as first bind variable and **statuses** as the second bind variable:
update results_dummy as rd
set status=new.status, updated_at=now()
from (select unnest(:1::int[]) as id,unnest(:2::text[]) as status) as new
where rd.id=new.id;
Came across similar scenario and the CASE expression was useful to me.
UPDATE reports SET is_default =
case
when report_id = 123 then true
when report_id != 123 then false
end
WHERE account_id = 321;
Reports - is a table here, account_id is same for the report_ids mentioned above. The above query will set 1 record (the one which matches the condition) to true and all the non-matching ones to false.
The answer provided by #zero323 works great on Postgre 12. In case, someone has multiple values for column_b (referred in OP's question)
UPDATE conupdate SET orientation_status = CASE
when id in (66934, 39) then 66
when id in (66938, 49) then 77
END
WHERE id IN (66934, 39, 66938, 49)
In the above query, id is analogous to column_b; orientation_status is analogous to column_a of the question.
In addition to other answers, comments and documentation, the datatype cast can be placed on usage. This allows an easier copypasting:
update test as t set
column_a = c.column_a::number
from (values
('123', 1),
('345', 2)
) as c(column_b, column_a)
where t.column_b = c.column_b::text;
#Roman thank you for the solution, for anyone using node, I made this utility method to pump out a query string to update n columns with n records.
Sadly it only handles n records with the same columns so the recordRows param is pretty strict.
const payload = {
rows: [
{
id: 1,
ext_id: 3
},
{
id: 2,
ext_id: 3
},
{
id: 3,
ext_id: 3
} ,
{
id: 4,
ext_id: 3
}
]
};
var result = updateMultiple('t', payload);
console.log(result);
/*
qstring returned is:
UPDATE t AS t SET id = c.id, ext_id = c.ext_id FROM (VALUES (1,3),(2,3),(3,3),(4,3)) AS c(id,ext_id) WHERE c.id = t.id
*/
function updateMultiple(table, recordRows){
var valueSets = new Array();
var cSet = new Set();
var columns = new Array();
for (const [key, value] of Object.entries(recordRows.rows)) {
var groupArray = new Array();
for ( const [key2, value2] of Object.entries(recordRows.rows[key])){
if(!cSet.has(key2)){
cSet.add(`${key2}`);
columns.push(key2);
}
groupArray.push(`${value2}`);
}
valueSets.push(`(${groupArray.toString()})`);
}
var valueSetsString = valueSets.join();
var setMappings = new String();
for(var i = 0; i < columns.length; i++){
var fieldSet = columns[i];
setMappings += `${fieldSet} = c.${fieldSet}`;
if(i < columns.length -1){
setMappings += ', ';
}
}
var qstring = `UPDATE ${table} AS t SET ${setMappings} FROM (VALUES ${valueSetsString}) AS c(${columns}) WHERE c.id = t.id`;
return qstring;
}
I don't think the accepted answer is entirely correct. It is order dependent. Here is an example that will not work correctly with an approach from the answer.
create table xxx (
id varchar(64),
is_enabled boolean
);
insert into xxx (id, is_enabled) values ('1',true);
insert into xxx (id, is_enabled) values ('2',true);
insert into xxx (id, is_enabled) values ('3',true);
UPDATE public.xxx AS pns
SET is_enabled = u.is_enabled
FROM (
VALUES
(
'3',
false
,
'1',
true
,
'2',
false
)
) AS u(id, is_enabled)
WHERE u.id = pns.id;
select * from xxx;
So the question still stands, is there a way to do it in an order independent way?
---- after trying a few things this seems to be order independent
UPDATE public.xxx AS pns
SET is_enabled = u.is_enabled
FROM (
SELECT '3' as id, false as is_enabled UNION
SELECT '1' as id, true as is_enabled UNION
SELECT '2' as id, false as is_enabled
) as u
WHERE u.id = pns.id;