Removing duplicate row from SQLite3 - sqlite

I have a SQLite3 DB with ~10,000 rows of data.
The schema is like this:
id, stock_id, body, stock_created_at, symbol, updated_at, created_at
The PK is id with no FK
You can tell there is a duplicate if the stock_id is duplicated.
I have a MySQL query like this that I used to use, but it's for MySQL and not SQLite:
DELETE FROM stocks WHERE id NOT IN
(SELECT MAX(id) FROM table GROUP BY stock_id);

Using SQLite3 (SQLite version 3.8.10.2 2015-05-20 18:17:19):
sqlite> create table test (id int, stock_id int, symbol text);
sqlite> insert into test values (1, 1, 'GOOG');
sqlite> insert into test values (2, 1, 'GOOGL');
sqlite> insert into test values (3, 2, 'AAPL');
sqlite> select * from test;
id stock_id symbol
---------- ---------- ----------
1 1 GOOG
2 1 GOOGL
3 2 AAPL
sqlite> delete from test
...> where id in (
...> select max(id) from test
...> group by stock_id
...> having count(*) > 1
...> );
sqlite> select * from test;
id stock_id symbol
---------- ---------- ----------
1 1 GOOG
3 2 AAPL
If stock table was a completely different table, the same concept works quite well:
sqlite> create table stock (stock_id int);
sqlite> insert into stock values (1);
sqlite> insert into stock values (2);
sqlite> insert into stock values (3);
sqlite> delete from stock
...> where stock_id in (
...> select max(id) from test
...> group by stock_id
...> having count(*) > 1
...> );
sqlite> select * from stock;
stock_id
----------
1
3
Does this kind of query work for you? If not, what SQLite version are you using and can you edit your question with example data?

Related

Use cursor from a modified table into the same PL/SQL procedure

I'm new in PL/SQL and I want to know how to resolve my problem. I actually want to insert some values into a table and after that insertion get values from this updated table and do some stuff into a new table.
So here's my example, I first insert some values from TABLE_1 into TABLE_2
CREATE or REPLACE PROCEDURE PROC_1 AS
CURSOR C1 IS SELECT DISTINCT COL1 FROM TABLE_1;
BEGIN
FOR REG IN C1 LOOP
BEGIN
INSERT INTO TABLE_2 (COL1) VALUES (REG.COL1);
END;
END LOOP;
END;
Now in a second time I want to retrieve all the rows of TABLE_2 and loop over the results to insert some values into a third table (TABLE_3)
How can I use a second CURSOR after the insertion of the values into TABLE_2 with the content of the updated TABLE_2 and then insert values in TABLE_3 into the same PROC_1 procedure?
Assuming that you have something to do on the table before using the values to insert into the third one, you can use exactly te same way you did the first insert:
CREATE or REPLACE PROCEDURE PROC_1 AS
CURSOR C1 IS SELECT DISTINCT COL1 FROM TABLE_1;
CURSOR C2 IS SELECT DISTINCT COL1 FROM TABLE_2;
BEGIN
FOR REG IN C1 LOOP
BEGIN
INSERT INTO TABLE_2 (COL1) VALUES (REG.COL1);
END;
END LOOP;
--
/* ... something ... */
--
FOR REG IN C2 LOOP
BEGIN
INSERT INTO TABLE_3 (COL1) VALUES (REG.COL1);
END;
END LOOP;
END;
For example:
SQL> select count(1) from table_1;
COUNT(1)
----------
2
SQL> select count(1) from table_2;
COUNT(1)
----------
0
SQL> select count(1) from table_3;
COUNT(1)
----------
0
SQL> exec proc_1;
PL/SQL procedure successfully completed.
SQL> select count(1) from table_2;
COUNT(1)
----------
2
SQL> select count(1) from table_3;
COUNT(1)
----------
2
SQL>
However, you don't need cursors for this and you could write a procedure like:
CREATE or REPLACE PROCEDURE PROC_2 AS
BEGIN
INSERT INTO TABLE_2 (COL1) SELECT COL1 FROM TABLE_1;
--
/* ... something ... */
--
INSERT INTO TABLE_3 (COL1) SELECT COL1 FROM TABLE_2;
END;
which gives:
SQL> DELETE TABLE_2;
2 rows deleted.
SQL> DELETE TABLE_3;
2 rows deleted.
SQL> EXEC PROC_2;
PL/SQL procedure successfully completed.
SQL> select count(1) from table_2;
COUNT(1)
----------
2
SQL> select count(1) from table_3;
COUNT(1)
----------
2
You can use global temp table for this purpose.
CREATE GLOBAL TEMPORARY TABLE my_temp_table (
id NUMBER,
description VARCHAR2(20)
)
ON COMMIT PRESERVE ROWS;
https://oracle-base.com/articles/misc/temporary-tables

Oracle PLSQL update table where in Associative Array?

I would like to, in a stored proc, update all the records that match an id.
Now, this list of id, is being passed in as a table of varchar (Associative Array)..
CREATE TYPE varcharArray AS TABLE OF VARCHAR2(1000) index by ...
and the proc declaration is something like
PROCEDURE testProc (p_IDs in varcharArray, p_Success out Number)
and the update statement in the proc
update testtable
set col = 'val'
where id in (select column_value from table(p_IDs);
This doesn't seem to work. So i had to do a loop in the array and update for each Id.
But i'd really like it to update using the where in clause.. Any help would be great.
PS: the id field is a number.
It works for me:
create table testtable (col varchar2(10), id varchar2(1000));
insert into testtable values (null, 'AAA');
insert into testtable values (null, 'BBB');
insert into testtable values (null, 'CCC');
insert into testtable values (null, 'DDD');
commit;
create or replace PROCEDURE testProc (p_IDs in varcharArray) is
begin
update testtable
set col = 'val'
where id in (select column_value from table(p_IDs));
end;
/
exec testproc(p_ids=>varcharArray('AAA','DDD'));
SQL> select * from testtable;
COL ID
---------- ----------
val AAA
BBB
CCC
val DDD

Update field to zero in one table when data for the respective field is not present in the other table in sqlite

I am using SQLite. There are two tables shown below.
Transaction_Tbl
ID Name Credit/Debit Value
1 ABC credit 10
1 ABC credit 10
2 DEF credit 20
2 DEF debit 40
(record for third employee EFG not present in the table)
Based on the table, Emp_Tbl must be updated as below...
Emp_Table
ID Name Avg(Credit-Debit)
1 ABC 20
2 DEF -20
3 EFG 0 (as no records for EFG in Transaction_Tbl)
Now if there is a record for EFG in Transaction_Tbl for Debit, then in Emp_Tbl, the record for EFG must be negative (credit - debit => where credit must be taken as zero as no records for credit.).
How to do it?
Assuming there's a table names listing all names (else where would efg sprint out from?!), then something like...:
sqlite> create table trans (id smallint, name string, cord string, value int);
sqlite> insert into trans(id,name,cord,value) values(1,'abc','credit',10);
sqlite> insert into trans(id,name,cord,value) values(1,'abc','credit',10);
sqlite> insert into trans(id,name,cord,value) values(2,'def','credit',20);
sqlite> insert into trans(id,name,cord,value) values(2,'def','debit',40);
sqlite> select * from trans;
1|abc|credit|10
1|abc|credit|10
2|def|credit|20
2|def|debit|40
sqlite> create table names (name string);
sqlite> insert into names(name) values('abc');
sqlite> insert into names(name) values('def');
sqlite> insert into names(name) values('efg');
to create and populate the tables and check the main one, then
sqlite> select names.name, sum(case trans.cord when 'credit' then trans.value when 'debit' then -trans.value else 0 end) from names left outer join trans on names.name=trans.name group by names.name;
abc|20
def|-20
efg|0
seems roughly what you're after, right?

Insert distinct records to table in sqlite3

I want to insert records from first table to second in such a way that only unique records get inserted. That is if table one and two has overlapping (duplicate) records, only the unique records get inserted into table one from table two. For example I have one table named Table_One,
and another table named Table_Two,
now I want to add the records from Table_Two the records that are not already in Table_one which is (XYZ | UVW) so that the output is,
I tried using this technique,
INSERT INTO TableB(Col1, Col2, Col3, ... , Coln)
SELECT DISTINCT A.Col1, A.Col2, A.Col3, ... , A.Coln
FROM TableA A
LEFT JOIN TableB B
ON A.KeyOfTableA = B.KeyOfTableB
WHERE B.KeyOfTableB IS NULL
but the duplicate rows also got inserted, any suggestions as to what could be the solution ??? I am using sqlite3 db.
INSERT INTO TableB (Col1, Col2, Col3, ... , Coln)
SELECT DISTINCT A.Col1,
A.Col2,
A.Col3,
... ,
A.Coln
FROM TableA A
WHERE A.KeyOfTableA NOT IN (SELECT B.KeyOfTableB
FROM TableB B)
Simply use UNION.
Query
sqlite> CREATE TABLE table1(firstName VARCHAR(50),lastName VARCHAR(50));
sqlite> INSERT INTO table1 VALUES('ABC','DEF');
sqlite> INSERT INTO table1 VALUES('GHI','JKL');
sqlite> INSERT INTO table1 VALUES('MNO','PQR');
sqlite>
sqlite> CREATE TABLE table2(first VARCHAR(50),last VARCHAR(50));
sqlite> INSERT INTO table2 VALUES('ABC','DEF');
sqlite> INSERT INTO table2 VALUES('XYZ','UVW');
sqlite> .headers ON
sqlite> SELECT * FROM table1 UNION SELECT * FROm table2;
OUTPUT
firstName|lastName
ABC|DEF
GHI|JKL
MNO|PQR
XYZ|UVW

How to return dynamic cursor from oracle stored procedure

I have 2 tables in which ID field is common.
I am fetching all records of first table in a cursor.
Then I want to do is that on the basis of each ID from cursor, I want to get the values from second table and then return that.
How can I do that...
Please help !!!
homework?
this is basic SQL. generally you'd join the two tables.
begin
for r_row in (select b.*
from tab1 a
inner join tab2 b
on b.id = a.id)
loop
null; -- do whatever
end loop;
end;
/
if you have an existing cursor and can't change it
eg where your_cursor is just returning an ID column.
begin
open your_cursor;
loop
fetch your_cursor into v_id;
exit when your_cursor%notfound;
for r_row in (select * from tab2 b where b.id = v_id)
loop
null; -- do whatever here.
end loop;
end loop;
end;
/
edit:
as per comments:
some sample data:
SQL> create table table1 (id number primary key, name varchar2(20));
Table created.
SQL> create table table2 (id number, col1 varchar2(20), col2 varchar2(20));
Table created.
SQL> insert into table1 values (1, 'test');
1 row created.
SQL> insert into table1 values (2, 'foo');
1 row created.
SQL>
SQL> insert into table2 values (1, 'John', 'Smith');
1 row created.
SQL> insert into table2 values (1, 'Peter', 'Jones');
1 row created.
SQL> insert into table2 values (1, 'Jane', 'Doe');
1 row created.
SQL> insert into table2 values (2, 'Nina', 'Austin');
1 row created.
SQL> insert into table2 values (2, 'Naman', 'Goyal');
1 row created.
SQL> commit;
Commit complete.
create a type to hold the return structure. note the datatypes NEED to match the datatypes of the tables table1 and table2 (%type won't work, so make sure they match)
SQL> create type my_obj as object (
2 id number,
3 name varchar2(20),
4 col1 varchar2(20),
5 col2 varchar2(20)
6 );
7 /
Type created.
SQL> create type my_tab as table of my_obj;
2 /
Type created.
now create your function (you can put this in a package if, in your real code, you have it that way).
SQL> create function function1
2 return my_tab pipelined
3 is
4 begin
5 for r_row in (select t1.id, t1.name, t2.col1, t2.col2
6 from table1 t1
7 inner join table2 t2
8 on t1.id = t2.id)
9 loop
10 pipe row(my_obj(r_row.id, r_row.name, r_row.col1, r_row.col2));
11 end loop;
12 end;
13 /
Function created.
SQL>
SQL> select *
2 from table(function1);
ID NAME COL1 COL2
---------- -------------------- -------------------- --------------------
1 test John Smith
1 test Peter Jones
1 test Jane Doe
2 foo Nina Austin
2 foo Naman Goyal
you could pass inputs if required into that function eg table(function1('a', 'b')); etc..

Resources