How to store updated rows in Snowflake? - snowflake-cloud-data-platform

I am looking for a replace of OUTPUT/RETURNING clause in SNOWFLAKE.
Test scenario:
I have a metadata tbl, in which I store all tables + columns which should be updated:
tblToUpdate
FieldToUpdate
tblA
name
tblA
lastname
tblB
middlename
tblC
address
tblC
phone
tblC
zipcode
I dynamically generate the upd stmt, based on this table and it looks like :
update tblA set name = '#tst', lastname = '#tst';
update tblB set middlename = '#tst';
update tblC set address = '#tst', phone ='#tst', zipcode = '#tst';
Next step is to create a log table, to store the names of the updated tables + ids of updated rows.
How can I do this without creating a STREAM tbl for each tbl to be updated (metadata tbl can contain from 1 to n tables, rows from it can change above the time). I need to find a way to create the log table, to keep a track of all changed tables with its rows.
Thanks!

Related

Retrieve data from table2 using column names stored in table1

I want to be able to look up fields values from a secondary table that stores the secondary table field names as strings in a primary table.
I am trying to both query the primary table itself to get the field names I want from the secondary table:
How can I use that string that contains the field name to select data from table2, given the id of a specific row.
The use case here, is that table1 also contains a note field. I want to populate that note field with the contents of a specific record in table2. I want to do this for all the records in table 1: each record references a different field by field name.
Another way to look at this:
Table2 has 1 row we want data from, and we know the ID
table1 stores the list of fields that we need data for from table 2
How do I get both pieces of data (field name, and field value) using these constraints?
all data is varchar
table1
fieldname
externalID
myField1
001
myField2
001
table2
id
myField1
myField2
myField3
001
myField1ValueForID001
myField2ValueForID001
myField3ValueForID001
002
moredata1
moredata2
moredata3
select fieldname,
(select [fieldname] from table2 where id = ) as fieldData
from table1
result
fieldname
fieldData
myField1
myField1
myField2
myField2
desired result
fieldname
fieldData
myField1
myField1ValueForID001
myField2
myField2ValueForID001
You can do this with a CASE expression, though I do recommend you rethink your design here:
SELECT *
INTO dbo.Table1
FROM (VALUES('myField1','001'),
('myField2','001'))V(FieldName,ExternalID);
SELECT *
INTO dbo.Table2
FROM (VALUES('001','myField1ValueForID001','myField2ValueForID001','myField3ValueForID001'),
('002','moredata1','moredata2','moredata3'))V(id,myField1,myField2,myField3);
GO
SELECT T1.FieldName,
CASE T1.FieldName WHEN 'myField1' THEN T2.myField1
WHEN 'myField2' THEN T2.myField2
WHEN 'myField3' THEN T2.myField3
END AS FieldData
FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.ExternalID = T2.id;
GO
DROP TABLE dbo.Table1;
DROP TABLE dbo.Table2;

SQL Select rows from 1st table and Update into 2nd Table

I have two tables, tblCity and tblCountry and there's no relationship between them at the moment. I need to add CountryIds from tblCountry into tblCity.
This is tblCity:
This is tblCountry:
I need to UPDATE tblCity.CountryId (which is NULL at the moment) with corresponding tblCountry.CountryId
I have ISO2 and ISO3 country codes in both tables, so please help me with select and update queries for SQL Server.
This statement will match on both ISO2 and ISO3 columns to do the update:
UPDATE
ci
SET
ci.CountryId = co.CountryId
FROM
tblCity ci
JOIN
tblCountry co
ON
ci.ISO2 = co.CountryISO2
AND
ci.ISO3 = co.CountryISO3
WHERE
ci.CountryId IS NULL

SQL Server 2012 UPDATE REPLACE with 2 columns from another table

I'm trying to update a column in one table (#TEMPTABLE) using data in another table (#PEOPLE) by using the REPLACE() function.
#TEMPTABLE has a column called "NameString' that is a long string with a user's name and ID.
#PEOPLE has a column for ID, and IDnumber.
UPDATE #TEMPTABLE
SET NAMEString = REPLACE(NAMEString, a.[ID], a.[IDNumber]) FROM #PEOPLE a
I'm trying to replace all the ID's in the NameString Column with the IDnumbers coming from #People table.
You need to give it a join criterion. For example:
update #TEMPTABLE
set NAMEString = replace(a.NAMEString, a.ID, b.IDNumber)
from #TEMPTABLE a
left join #PEOPLE b
on a.id = b.ID
Also, make sure to reference the right table when you use the IDNumber column - your original query doesn't actually use the table containing IDNumber at all, as far as I can tell from your description of your tables.
Note that my example assumes there's an ID field in #TempTable, or something else to join on - otherwise, you may need to extract it from the NameString column first.

2 nvarchar fields are not matching though the data is same?

I want to join 2 tables using an Inner Join on 2 columns, both are of (nvarchar, null) type. The 2 columns have the same data in them, but the join condition is failing. I think it is due to the spaces contained in the column values.
I have tried LTRIM, RTRIM also
My query:
select
T1.Name1, T2.Name2
from
Table1 T1
Inner Join
Table2 on T1.Name1 = T2.Name2
I have also tried like this:
on LTRIM(RTRIM(T1.Name1)) = LTRIM(RTRIM(T2.Name2))
My data:
Table1 Table2
------ ------
Name1(Column) Name2(Column)
----- ------
Employee Data Employee Data
Customer Data Customer Data
When I check My data in 2 tables with
select T1.Name1,len(T1.Name1)as Length1,Datalength(T1.Name1)as DataLenght1 from Table1 T1
select T2.Name2,len(T2.Name2)as Length2,Datalength(T2.Name2)as DataLenght2 from Table2 T2
The result is different Length and DataLength Values for the 2 tables,They are not same for 2 tables.
I can't change the original data in the 2 tables. How can I fix this issue.
Thank You
Joins do not have special rules for equality. The equality operator always works the same way. So if a = b then the join on a = b would work. Therefore, a <> b.
Check the contents of those fields. They will not be the same although you think they are:
select convert(varbinary(max), myCol) from T
Unicode has invisible characters (that only ever seem to cause trouble).
declare #t table (name varchar(20))
insert into #t(name)values ('Employee Data'),('Customer Data')
declare #tt table (name varchar(20))
insert into #tt(name)values ('EmployeeData'),('CustomerData')
select t.name,tt.name from #t t
INNER JOIN #tt tt
ON RTRIM(LTRIM(REPLACE(t.name,' ',''))) = RTRIM(LTRIM(REPLACE(tt.name,' ','')))
I would follow the following schema
Create a new table to store all the possible names
Add needed keys and indexes
Populate with existing names
Add columns to your existing tables to store the index of the name
Create relative foreign keys
Populate the new columns with correct indexes
Create procedure to perform an insert in new tables names only in case the value is not existing
Perform the join using the new indexes

Trigger that inserts only updated column names

I have created trigger that inserts names of the columns changed (insert, update, delete) in the audit table.
I have problem when I update columns. Lets say I have a table dbo.TABLE with columns COL1, COL2, COL3.
Further, lets say that I only have one row:
COL1 | COL2 | COL3
---------------------------
value1 | value2 | value3
If my update statement looks like this:
Update dbo.TABLE set COL1 = 'test1', COL2 = 'test2';
In my audit table will be inserted:
UPDATED
-------
COL1, COL2
This is OK, but lets say I have same table dbo.TABLE with first values (value1, value2, value3).
If my update statement looks like this:
Update dbo.TABLE set COL1 = 'value1', COL2 = 'test2';
In my audit table same result will be inserted as above (COL1, COL2).
How can I alter my trigger so only updated column (COL2) will be inserted?
I need some kind of statement that will check value of column before updating.
My trigger is too big to put all of it here, so I will only put part of the code that returns columns updated.
SELECT #idTable = T.id
FROM sysobjects P JOIN sysobjects T ON P.parent_obj = T.id
WHERE P.id = ##procid
SELECT #Columns_Updated = ISNULL(#Columns_Updated + ', ', '') + name
FROM syscolumns t
WHERE id = #idTable
AND CONVERT(VARBINARY,REVERSE(COLUMNS_UPDATED())) & POWER(CONVERT(BIGINT, 2), colorder - 1) > 0
This is original post from where I have taken the code:
SQL Server Update Trigger, Get Only modified fields
Are you able to prevent updates if the values are identical? This would be the best approach, and allow you to use the same code you have in your trigger (not to mention far more efficient from an i/o perspective).
If the front end driving the updates is a UI, then I would drop a logging class in it to record before/after data using that.
Failing that, I think (someone else might correct me here) you'd need to use CDC (change data capture) to compare old/new values.

Resources