Snowflake stream behavior - stream

I have following fields in table 1-
db,schema,jobnm,status,runtime, ins_tstmp, upd_tstmp.
A stream has been created on table 1.
A stored procedure was written to loop through another table's dataset (4 records) and write all 4 records to table 1 if they don't already exist else update (using merge sql here; ins_tstmp gets populated via insert part of merge while upd_tstmp gets updated via update part ).
As expected, table1 has all 4 records and Stream also has 4 records with metadata$action as INSERT . UPD_TSTMP is null here.
Now on 2nd run, same 4 records were retrieved. Since they were a match, upd_tstmp got populated in both table 1 and stream but why metadata$action is INSERT only? Not seeing 2 entries for an update. Could someone please explain what I am missing here?
Thanks

Since they were a match, upd_tstmp got populated in both table 1 and
stream but why metadata$action is INSERT only?
The METADATA$ACTION column can have 2 possible values: INSERT and DELETE. So you can't see "UPDATE" in this column.
METADATA$ISUPDATE: This is an extra column indicating whether the operation was part of an UPDATE statement. In your case, you should also see it "false" because Streams record the differences between two offsets. If a row is added and then updated in the current offset, the delta change is a new row. The METADATA$ISUPDATE row records a FALSE value.
https://docs.snowflake.com/en/user-guide/streams-intro.html#stream-columns

Related

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

Using FireDac to update only 1 of a duplicate row (no primary key or unique field)

I have an old application I am supporting that uses a Microsoft Access database. The original table design did not add primary keys to every table. I am working on a migration program that among other things is adding and filling in a new primary key field (GUID) when needed.
This is happening in three steps:
Add a new guid field with no constraints
Fill the field with new unique guids
Add the primary key constraints
My problem is setting the unique guids when the table has duplicate rows. Here is my code to set the guids.
Query.SQL.Add('SELECT * FROM ' + TableName);
Query.Open;
while Query.Eof = false do
begin
Query.Edit;
Query.FieldByName(NewPrimaryKeyFieldName).AsGuid := TGuid.NewGuid;
Query.Post;
Query.Next;
end;
FireDac generates an update statement that contains a where clause with all the original fields/values in the row (since there is no unique field for it to use). However, because the rows are complete duplicates the statement still updates two rows.
FireDac correctly errors with this message
Update command updated [2] instead of [1] record.
I can open up the database in Access and delete the duplicate records or assign them a unique guid by editing the table. I would like my conversion tool to automatically do this.
Is there some way to work with these duplicate rows in FireDac? Either to update just one at a time, or to delete just one of them?
In my opinion there is no way to do it with just one SQL Statement.
I would do this:
1. Copy the whole table without duplicates by using a new temp table
SELECT DISTINCT * FROM <TABLENAME>
Add the Keys
Delete old table content and copy new content from new table
Notes:
The DB Should be unavailable for everyone else for that Operation
2. Make BACKUP before

Are indexed columns with NULL values ignored by the cost-based optimizer?

I have a voter table with ~640M rows that has a DateOfDeath DATE column which is indexed.
~410M of the rows have NULL values in DateOfDeath column because these voters are still alive.
If I do a query to select all rows with DateOfDeath between "01012015" and "12312015", will the optimizer bypass all rows that have NULL values in DateOfDeath, without having to do a full table scan?
It will depend on the query, but the query would probably use the index on DateOfDeath and would certainly not need to scan the range of the index where the DateOfDeath is NULL in order to answer that query. You'd need to be sure you've run UPDATE STATISTICS recently if your version of Informix is older than about 11.50.

Oracle: Procedure to Update rows, and the return the updated rows in sys_refcursor

I want to do something like
update example_table
set field1=xx
where field2=someValue;
(here I want to open a sys_refcursor) with only the updated rows and return it.
Regards
One way is to add a column to your table (f.e. status varchar(1) default '-') and if updated, set status 'U', inserted -'I' etc...
Then You can just do select on this rows or whatever You want (Bulk Collect for example).

Firebird Insert Distinct Data Using ZeosLib and Delphi

I'm using Zeos 7, and Delphi 2009 and want to check to see if a value is already in the database under a specific field before I post the data to the database.
Example: Field Keyword
Values of Cheese, Mouse, Trap
tblkeywordKEYWORD.Value = Cheese
What is wrong with the following? And is there a better way?
zQueryKeyword.SQL.Add('IF NOT EXISTS(Select KEYWORD from KEYWORDLIST ='''+
tblkeywordKEYWORD.Value+''')INSERT into KEYWORDLIST(KEYWORD) VALUES ('''+
tblkeywordKEYWORD.Value+'''))');
zQueryKeyword.ExecSql;
I tried using the unique constraint in IBExpert, but it gives the following error:
Invalid insert or update value(s): object columns are
constrained - no 2 table rows can have duplicate column values.
attempt to store duplicate value (visible to active transactions) in unique index "UNQ1_KEYWORDLIST".
Consider to use UPDATE OR INSERT or MERGE statements:
update or insert into KEYWORDLIST (KEYWORD) values(:KEYWORD) matching(KEYWORD)
For details check the following documents in your Firebird installation folder:
doc\sql.extensions\README.update_or_insert.txt
doc\sql.extensions\README.merge.txt

Resources