How to get the last updated value of a value in sql - teradata

sample data I have 2 columns old_store_id, changed_new_store_id and there are cases when changed_new_store_id value will also get updated to new value. how can i traverse through DB(teradata) to get the last value (changed_new_store_id ) of the respective old_store_id
let say in 1 st row
old_store_id = A ;
changed_new_store_id = B
and 5 th row contains
old_store_id = B ;
changed_new_store_id = C
and some other nth row C is changed to X etc
how to get final value of A which is X ?
I can try using multiple self joins
using Stored procedure but it will not be an efficient way (for many reasons)
Is there any way to find ?
Please anyone suggest me

This assumes no "loops", and uses "bottom-up" recursion. Something very similar could be done "top-down", limiting the seed query to rows where the "old" value doesn't appear anywhere as a "new" value.
CREATE VOLATILE TABLE #Example (
Old_Store_ID VARCHAR(8),
New_Store_ID VARCHAR(8)
)
PRIMARY INDEX(Old_Store_ID)
ON COMMIT PRESERVE ROWS;
INSERT INTO #Example VALUES ('A', 'B');
INSERT INTO #Example VALUES ('D', 'c');
INSERT INTO #Example VALUES ('B', 'F');
INSERT INTO #Example VALUES ('c', 'FF');
INSERT INTO #Example VALUES ('FF', 'GG');
INSERT INTO #Example VALUES ('F', 'X');
WITH RECURSIVE #Traverse(Old_Store_ID,New_Store_ID,Final_ID)
AS
(
--Seed Query - start with only the rows having no further changes
SELECT Old_Store_ID
,New_Store_ID
,New_Store_ID as Final_ID
FROM #Example as This
WHERE NOT EXISTS (
SELECT 1 FROM #Example AS Other WHERE This.New_Store_ID = Other.Old_Store_ID
)
UNION ALL
--Recursive Join
SELECT NewRow.Old_Store_ID
,NewRow.New_Store_ID
,OldRow.Final_ID
FROM #Example AS NewRow
INNER JOIN #Traverse AS OldRow
ON NewRow.New_Store_ID = OldRow.Old_Store_ID
)
SELECT *
FROM #Traverse
;

A recursive answer:
CREATE VOLATILE TABLE #SearchList (
SearchID CHAR(2),
ParentSearchID CHAR(2)
)
PRIMARY INDEX(SearchID)
ON COMMIT PRESERVE ROWS;
INSERT INTO #SearchList VALUES ('A', 'B');
INSERT INTO #SearchList VALUES ('D', 'c');
INSERT INTO #SearchList VALUES ('B', 'F');
INSERT INTO #SearchList VALUES ('c', 'FF');
INSERT INTO #SearchList VALUES ('FF', 'GG');
INSERT INTO #SearchList VALUES ('F', 'X');
CREATE VOLATILE TABLE #IntermediateResults(
SearchID CHAR(2),
ParentSearchID CHAR(2),
SearchLevel INTEGER
)
ON COMMIT PRESERVE ROWS;
INSERT INTO #IntermediateResults
WITH RECURSIVE RecursiveParent(SearchID,ParentSearchID,SearchLevel)
AS
(
--Seed Query
SELECT SearchID
,ParentSearchID
,1
FROM #SearchList
UNION ALL
--Recursive Join
SELECT a.SearchID
,b.ParentSearchID
,SearchLevel+1
FROM #SearchList a
INNER JOIN RecursiveParent b
ON a.ParentSearchID = b.SearchID
)
SELECT SearchID
,ParentSearchID
,MAX(SearchLevel)
FROM RecursiveParent
GROUP BY SearchID
,ParentSearchID
;
SELECT RESULTS.*
FROM #IntermediateResults RESULTS
INNER JOIN (SELECT RESULTS_MAX.SearchID
,MAX(RESULTS_MAX.SearchLevel) MaxSearchLevel
FROM #IntermediateResults RESULTS_MAX
GROUP BY RESULTS_MAX.SearchID
) GROUPED_RESULTS
ON RESULTS.SearchID = GROUPED_RESULTS.SearchID
AND RESULTS.SearchLevel = GROUPED_RESULTS.MaxSearchLevel
ORDER BY RESULTS.SearchID ASC
,RESULTS.SearchLevel ASC
;
Output:
SearchID ParentSearchID SearchLevel
-------- -------------- -----------
A X 3
B X 2
c GG 2
D GG 3
F X 1
FF GG 1

Related

Column with keywords found in comments field

At work I've been given a task that I'm told is "simple and straightforward", but I'm having difficulty with:
I have a view that contains 4 columns, a PK, FK, comments, and column #4. My manager is telling me to make a table that contains 75 or so keywords, and then a query that will go through each row in the view, compare the comments to the keyword table, and then append each found keyword to column #4. I've searched google and SO, and have not found a query that would do this. Any help would be appreciated.
Try below. I am new to Teradata.
--***************************************************************
DROP TABLE x;
--***************************************************************
CREATE MULTISET VOLATILE TABLE x, NO FALLBACK,
CHECKSUM = DEFAULT,
LOG
(
RCD_ID INTEGER,
FK INTEGER,
CMT VARCHAR(200),
COL_4 VARCHAR(200),
RN INTEGER
)
PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
INSERT INTO x VALUES (1,10,'DID YOU SEE THE COW?','',0);
INSERT INTO x VALUES (2,20,'DID YOU SEE THE CAT?','',0);
INSERT INTO x VALUES (3,30,'DID YOU SEE THE FOX?','',0);
INSERT INTO x VALUES (4,40,'DID YOU SEE THE GOAT, FOX, AND CAT?','',0);
INSERT INTO x VALUES (5,50,'DID YOU SEE THE DUCK AND THE COW?','',0);
--***************************************************************
SELECT * FROM x ORDER BY 1;
--***************************************************************
DROP TABLE y;
--***************************************************************
CREATE MULTISET VOLATILE TABLE y, NO FALLBACK,
CHECKSUM = DEFAULT,
LOG
(
RCD_ID INTEGER,
KEY_WORD VARCHAR(20)
)
PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
INSERT INTO y VALUES (1,'COW');
INSERT INTO y VALUES (2,'CAT');
INSERT INTO y VALUES (3,'FOX');
INSERT INTO y VALUES (4,'GOAT');
INSERT INTO y VALUES (5,'DUCK');
--***************************************************************
SELECT * FROM y ORDER BY 1;
--***************************************************************
DROP TABLE z;
--***************************************************************
CREATE MULTISET VOLATILE TABLE z AS(
SELECT x.RCD_ID,x.CMT,x.COL_4,y.key_word, ROW_NUMBER() OVER(PARTITION BY x.RCD_ID ORDER BY x.RCD_ID) AS RN
FROM x JOIN y ON x.cmt LIKE '%' || y.KEY_WORD || '%'
)
WITH DATA PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
SELECT * FROM z ORDER BY 1,5;
--***************************************************************
WITH RECURSIVE RPT AS(
SELECT
RCD_ID,FK,CMT,COL_4,RN
FROM x
UNION ALL
SELECT
b.RCD_ID,b.FK,b.CMT,b.COL_4 || ';' || a.KEY_WORD,a.RN
FROM z AS a
JOIN RPT AS b
ON b.RCD_ID = a.RCD_ID
AND b.RN = a.RN-1
)
SELECT *
FROM RPT
QUALIFY ROW_NUMBER() OVER (PARTITION BY RCD_ID ORDER BY RCD_ID, RN DESC) = 1
ORDER BY 1,5;
--***************************************************************

Updating single specified values from another table in SQLite

I have two SQLite tables A and B defined as:
CREATE TABLE A (orig_cat INTEGER, type INTEGER,gv_ID INTEGER);
INSERT INTO A (orig_cat,type) VALUES (1,1);
INSERT INTO A (orig_cat,type) VALUES (2,2);
INSERT INTO A (orig_cat,type) VALUES (3,2);
INSERT INTO A (orig_cat,type) VALUES (4,2);
INSERT INTO A (orig_cat,type) VALUES (1,3);
INSERT INTO A (orig_cat,type) VALUES (2,3);
INSERT INTO A (orig_cat,type) VALUES (3,3);
UPDATE A SET gv_ID=rowid+99;
and
CREATE TABLE B (col_t INTEGER, orig_cat INTEGER, part INTEGER);
INSERT INTO B VALUES (1,1,1);
INSERT INTO B VALUES (3,1,2);
INSERT INTO B VALUES (2,2,1);
INSERT INTO B VALUES (1,2,2);
INSERT INTO B VALUES (3,3,1);
INSERT INTO B VALUES (4,3,2);
I'd like to update and set/replace the values in column col_t of table B where part=2 with selected values of column gv_ID of table A. The selected values I can get with a SELECT command:
SELECT gv_ID
FROM (SELECT * FROM B where part=2) AS B_sub
JOIN (SELECT * FROM A WHERE type=3) AS A_sub
ON B_sub.orig_cat=A_sub.orig_cat;
How can I use that so that the values of col_t in rows 2,3 and 5 (=1,2,3) get replaced with the values 104,105,106 (wich is returned by the selection)?
You can use correlated subquery:
UPDATE B
SET col_t = (SELECT gv_ID FROM A WHERE A.orig_cat = B.orig_cat AND A.type = 3)
WHERE B."part" = 2;
SqlFiddleDemo
I've assumed that pair A.orig_cat and A.type is UNIQUE.

SQLite cross reference unique combinations

I've got two tables already populated with data with the given schemas:
CREATE TABLE objects
(
id BIGINT NOT NULL,
latitude BIGINT NOT NULL,
longitude BIGINT NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE tags
(
id BIGINT NOT NULL,
tag_key VARCHAR(100) NOT NULL,
tag_value VARCHAR(500),
PRIMARY KEY (id , tag_key)
)
object.id and tags.id refer to the same object
I'd like to populate a third table with the unique combinations of tag_key and tag_value. For example:
INSERT OR REPLACE INTO objects (id) VALUES (0);
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (0, 'a', 'x');
INSERT OR REPLACE INTO objects (id) VALUES (1);
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (1, 'a', 'y');
INSERT OR REPLACE INTO objects (id) VALUES (2);
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (2, 'a', 'x');
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (2, 'a', 'y');
INSERT OR REPLACE INTO objects (id) VALUES (3);
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (3, 'a', 'x');
INSERT OR REPLACE INTO objects (id) VALUES (4);
INSERT OR REPLACE INTO tags (id, tag_key, tag_value) VALUES (4, 'a', 'y');
Should result in 3 entries of
0: ([a,x])
1: ([a,y])
3: ([a,x][a,y])
Currently I have:
CREATE TABLE tags_combinations
(
id INTEGER PRIMARY KEY,
tag_key VARCHAR(100) NOT NULL,
tag_value VARCHAR(500)
);
The id shouldn't be related to the original id of the object, just something to group unique combinations.
This is the query I have so far:
SELECT
t1.tag_key, t1.tag_value
FROM
tags t1
WHERE
t1.id
IN
(
/* select ids who's every tags entry is not under one id in tags_combinations */
SELECT
t2.id
FROM
tags t2
WHERE
t2.tag_key, t2.tag_value
NOT IN
(
)
);
The part with the comment is what I am not sure about, how would I select every id from tags that does not have all of the corresponding tag_key and tag_value entries already under one id in tags_combinations?
To clarify exactly the result I am after: From the sample data given, it should return 4 rows with:
row id tag_key tag_value
0 0 a x
1 1 a y
2 2 a x
3 2 a y
SQL is a set-based language. If you reformulate your question in the language of set theory, you can directly translate it into SQL:
You want all rows of the tags table, except those from duplicate objects.
Objects are duplicates if they have exactly the same key/value combinations. However, we still want to return one of those objects, so we define duplicates only as those objects where no other duplicate object with a smaller ID exists.
Two objects A and B have exactly the same key/value combinations if
all key/value combinations in A also exist in B, and
all key/value combinations in B also exist in A.
All key/value combinations in A also exist in B if there is no key/value combination in A that does not exist in B (note: double negation).
SELECT id, tag_key, tag_value
FROM tags
WHERE NOT EXISTS (SELECT 1
FROM tags AS dup
WHERE dup.id < tags.id
AND NOT EXISTS (SELECT 1
FROM tags AS A
WHERE A.id = tags.id
AND NOT EXISTS (SELECT 1
FROM tags AS B
WHERE B.id = dup.id
AND B.tag_key = A.tag_key
AND B.tag_value = A.tag_value)
)
AND NOT EXISTS (SELECT 1
FROM tags AS B
WHERE B.id = dup.id
AND NOT EXISTS (SELECT 1
FROM tags AS A
WHERE A.id = tags.id
AND A.tag_key = B.tag_key
AND A.tag_value = B.tag_value)
)
)
ORDER BY id, tag_key;
This is not easy in SQLite. We want to identify groups of tag key/value pairs. So we could group by id and get a string of the associated pairs with group_concat. This would be the way to do it in another DBMS. SQLite, however, cannot order in group_concat, so we might end up with 2: 'a/x,a/y' and 5: 'a/y,a/x'. Two different strings for the same pairs.
Your best bet may be to write a program and find the distinct pairs iteratively.
In SQLite you may want to try this:
insert into tags_combinations (id, tag_key, tag_value)
select id, tag_key, tag_value
from tags
where id in
(
select min(id)
from
(
select id, group_concat(tag_key || '/' || tag_value) as tag_pairs
from
(
select id, tag_key, tag_value
from tags
order by id, tag_key, tag_value
) ordered_data
group by id
) aggregated_data
group by tag_pairs
);
Ordering the data before applying group_concat is likely to get the tag pairs ordered, but in no way guaranteed! If this is something you want to do only once, it may be worth a try, though.
To merge multiple rows into one value, you need a function like group_concat().
The ORDER BY is needed to ensure a consistent order of the rows within a group:
SELECT DISTINCT group_concat(tag_key) AS tag_keys,
group_concat(tag_value) AS tag_values
FROM (SELECT id,
tag_key,
tag_value
FROM tags
ORDER BY id,
tag_key,
tag_value)
GROUP BY id;
If you want to have keys and values interleaved, as shown in the question, you need to do more string concatenation:
SELECT DISTINCT group_concat(tag_key || ',' || tag_value, ';') AS keys_and_values
FROM (...

SQLite trigger insert/replace multiple rows multiple tables

I am attempting to respond to the insertion of a row in one table (A) to create or update multiple rows in a second table (B) based on the values of a third table (C) (which can be joined to the first).
I have the following construct,
CREATE TRIGGER MyTrigger AFTER INSERT ON A
BEGIN
INSERT OR REPLACE INTO B (ID, T1, T2, Role)
VALUES
(
( SELECT ID FROM C WHERE R1 = NEW.R1 ),
NEW.T1,
B.T2, -- The existing row's T2
( SELECT Role FROM C WHERE R1 = NEW.R1 ),
)
END;
Table A has columns ID, T1, R1
Table B has columns ID, T1, T2, Role
Table C has columns ID, R1, R2, Role
I have at least two problems with my attempts at composing the trigger
I don't know how to reference B's existing values in the REPLACE case, thus the "B.T2"
I don't know how to reference multiple columns (R1, Role) from the same row in table C when doing my INSERT/REPLACE in table B.
Thanks for any help in sorting this out.
Using SELECT instead of VALUES:
CREATE TRIGGER MyTrigger AFTER INSERT ON A BEGIN
INSERT OR REPLACE INTO B (ID, T1, T2, Role) SELECT
(SELECT ID FROM C WHERE R1 = NEW.R1),
NEW.T1,
B.T2,
(SELECT Role FROM C WHERE R1 = NEW.R1)
FROM B WHERE ROWID=NEW.ROWID
END;
I was able to use a LEFT OUTER JOIN on the SELECT so that all the needed values can be named regardless of whether there's an existing row.
CREATE TRIGGER MyTrigger AFTER INSERT ON A
BEGIN
INSERT OR REPLACE INTO B (ID, T1, T2, Role)
SELECT
C.ID,
NEW.T1,
B.T2,
C.Role
FROM C LEFT OUTER JOIN B ON C.ID = B.ID WHERE C.R1 = NEW.R1;
END;
To find the B record, just use a subquery like you're doing with C.
The B.ID value to search for is the same as that you're trying to insert.
CREATE TRIGGER MyTrigger
AFTER INSERT ON A
BEGIN
INSERT OR REPLACE INTO B (ID, T1, T2, Role)
VALUES
(
( SELECT ID FROM C WHERE R1 = NEW.R1 ),
NEW.T1,
( SELECT T2 FROM B WHERE ID = ( SELECT ID FROM C WHERE R1 = NEW.R1 ) ),
( SELECT Role FROM C WHERE R1 = NEW.R1 )
);
END;

How can I rewrite a multi-column IN clause to work on SQLite?

I've got a query that looks something like this:
SELECT
*
FROM table
WHERE
(col1, col2) in (
('col1_val1', 'col2_val1'),
('col1_val2', 'col2_val2'),
('col1_val3', 'col2_val3'),
)
This works in MySQL, but fails in sqlite3 with a syntax error:
Error: near ",": syntax error
How can I rewrite this query to an equivalent one that works in sqlite3?
Choose your favourite version:
http://sqlfiddle.com/#!5/6169b/9
using temporary table
CREATE TEMPORARY TABLE pair (a INTEGER, b INTEGER);
INSERT INTO pair (a, b) VALUES (1, 1);
INSERT INTO pair (a, b) VALUES (2, 2);
....
data IN pairs; if pair(a,b) is not unique
SELECT *
FROM data
WHERE EXISTS (
SELECT NULL
FROM pair
WHERE pair.a = data.a
AND pair.b = data.b
);
data IN pairs; if pair(a,b) is unique
SELECT data.*
FROM data
INNER JOIN pair
ON pair.a = data.a
AND pair.b = data.b;
data NOT IN pairs; if pair(a,b) is unique
SELECT data.*
FROM data
LEFT JOIN pair
ON pair.a = data.a
AND pair.b = data.b
WHERE pair.a IS NULL
OR pair.b IS NULL;
using inline table
data IN pairs; if pair(a,b) is not unique
SELECT *
FROM data
WHERE EXISTS (
SELECT NULL
FROM (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 2 AS a, 2 AS b
UNION ALL
SELECT 3 AS a, 3 AS b
) AS pair
WHERE pair.a = data.a
AND pair.b = data.b
);
data IN pairs; if pair(a,b) is unique
SELECT data.*
FROM data
INNER JOIN (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 2 AS a, 2 AS b
UNION ALL
SELECT 3 AS a, 3 AS b
) AS pair
ON pair.a = data.a
AND pair.b = data.b;
data NOT IN pairs; if pair(a,b) is unique
SELECT data.*
FROM data
LEFT JOIN (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 2 AS a, 2 AS b
UNION ALL
SELECT 3 AS a, 3 AS b
) AS pair
ON pair.a = data.a
AND pair.b = data.b
WHERE pair.a IS NULL
OR pair.b IS NULL;
Here's an easy solution that works, but it might not perform well on large data sets because it can't use any of your indexes.
SELECT * FROM table
WHERE col1 || '-' || col2 in (
'col1_val1-col2_val1',
'col1_val2-col2_val2',
'col1_val3-col2_val3'
)
Try it in sqlfiddle
Enjoy!
In sqlite try to add the VALUES keyword:
SELECT *
FROM table
WHERE
(col1, col2) in ( VALUES --> add this keyword and remove the last ,
('col1_val1', 'col2_val1'),
('col1_val2', 'col2_val2'),
('col1_val3', 'col2_val3')
)
Basically in sqLite executing the query:
VALUES
('col1_val1', 'col2_val1'),
('col1_val2', 'col2_val2');
is the same as:
SELECT 'col1_val1' AS column1, 'col2_val1' AS column2
UNION
SELECT 'col1_val2' AS column1, 'col2_val2' AS column2;
or combined:
SELECT 'col1_val1' AS column1, 'col2_val1' AS column2
UNION VALUES ('col1_val2', 'col2_val2');
So you could even write it like:
SELECT *
FROM table
WHERE (col1, col2) IN (
SELECT 'col1_val1', 'col2_val1'
UNION
SELECT 'col1_val2', 'col2_val2'
);
which is a simple subquery and works in all/most databases.

Resources