SQLite trigger insert/replace multiple rows multiple tables - sqlite

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;

Related

I need only one unique result in Oracle sdo_nn Update sentence ,

I need Only one unique result from tableB.Field to tableA.Field
I am using sdo operator sdo_nn, this is the code:
UPDATE table1 t1
SET t1.fieldA = (SELECT T2.fieldB,SDO_NN_DISTANCE(1) distance
FROM table1 T1, table2 T2
WHERE
(sdo_nn(t1.geometry,t2.geometry,'SDO_NUM_RES=1',1)= 'TRUE')
ORDER BY DIST
)
WHERE EXISTS(
SELECT 1
FROM table2 t2
WHERE sdo_nn(t1.geometry, t2.geometry,'SDO_NUM_RES=1',1)='TRUE'
AND(t2.cell_name = 'string1' or t2.cell_name = string2')AND t1.fieldA = NULL
);
In the select sentence of the subquery i get an error because i only use one field(t1.fieldA), but in the sentence i use the operator SDO_NN_DISTANCE(1) and the sql developer count this operator like another field. What is the correct way to write this sentence? I only use sql because i need to insert this code in vba
Thanks!!!
Obviously, you can't (simplified)
set t1.fieldA = (t2.fieldB, distance) --> you want to put two values into a single column
Therefore, get fieldB alone from the subquery which uses analytic function (row_number) to "sort" rows by sdo_nn_distance(1) desc; then get the first row's fieldB value.
Something like this (I hope I set the parenthesis right):
UPDATE table1 t1
SET t1.fieldA =
(SELECT x.fieldB --> only fieldB
FROM (SELECT T2.fieldB, --> from your subquery
SDO_NN_DISTANCE (1) distance,
ROW_NUMBER ()
OVER (ORDER BY sdo_nn_distance (1) DESC) rn
FROM table1 T1, table2 T2
WHERE (sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE')) x
WHERE rn = 1) --> where RN = 1
WHERE EXISTS
(SELECT 1
FROM table2 t2
WHERE sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE'
AND ( t2.cell_name = 'string1'
OR t2.cell_name = 'string2')
AND t1.fieldA IS NULL);

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

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

Use for loop in Teradata SQL

I would like to do this in teradata SQL/ MACRO or PROCEDURE :
CREATE MACRO insertloop ( val1 VARCHAR( 1000)) AS
(
sublist_i = ' SELECT sublist from table3 '
FOR sublist_i in sublist :
INSERT INTO table5
SELECT t.id, t.address, sum(t.amount)
FROM table2 AS t
WHERE
t.id in sublist_i
AND t.address = :val1
GROUP BY t.id t.address
);
Explanation:
table3 contains list of id (by block of 1000 id)
(12, 546, 999)
(45,789)
(970, 990, 123)
Main reason :
table2 is very huge (1 billion record).
A full join requires too much memory, we need
to create a table table3 containing disjoint list of id
and iterate on this list.
But, am not sure how to correct this MACRO to be make correct.

Proc sql to Pull data from different tables recursively

I need to perform a recursive count operation on tables but here are the challenges that I am facing with.
Lets say I have tables A, B, C, D, E, F, .... Z
Here is the code snippet of what I have,
Proc sql;
create table temp as(
select count(*)
from a
inner join b on a.id = b.id
inner join c on a.id = c.id
inner join d on a.id = d.id
where <condition>
);
Once this code is complete I need to run the same query with B, C, D and E and update the result in same temp table that I am trying to create. This way I have to do for the entire table list that I have.
Is there a recursive sql to do this. I don't require a separate macro to call the query each time with different tables.
I would not do it quite this way.
proc sql;
create table temp as (
select count(case when n(a.id,b.id,c.id,d.id)=4 then 1 else 0 end) as abcd_count,
count(case when n(b.id,c.id,d.id,e.id)=4 then 1 else 0 end) as bcde_count
from a outer join b on a.id=b.id
outer join c ... etc.
;
quit;
IE, just do one join and use case when... to determine what has the counts you need. Here I use n() to identify records with all 4 ids on them.

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