Compare two tables in SQLite - sql

I have two tables in the database MyTable and MyTableChanges. I want to detect changes (which records were inserted/removed from MyTableChanges or edited).
Is it possible? I would like to do this using only SQLite queries.
I know I can use 2 queries like the one below to detect inserted and removed rows:
SELECT DISTINCT SomePrimaryKey
FROM MyTable
WHERE SomePrimaryKey Not IN
(SELECT DISTINCT SomePrimaryKey FROM MyTableChanges)
But how to compare changes? Maybe there's some way, dealing with hashes on columns and joins. I don't know how to start. Please, advise me!
EDIT
I know I can do something like this:
CREATE TABLE Test1
(
MI_PRINX INTEGER PRIMARY KEY AUTOINCREMENT,
Name CHAR(100),
Value INTEGER
);
CREATE TABLE Test2
(
MI_PRINX INTEGER PRIMARY KEY AUTOINCREMENT,
Name CHAR(100),
Value INTEGER
);
INSERT INTO Test1 (Name, Value) VALUES('Name1', 1);
INSERT INTO Test1 (Name, Value) VALUES('Name2', 2);
INSERT INTO Test1 (Name, Value) VALUES('Name3', 3);
INSERT INTO Test1 (Name, Value) VALUES('Name4', 4);
INSERT INTO Test2 (Name, Value) VALUES('Name1', 2);
INSERT INTO Test2 (Name, Value) VALUES('Name3', 3);
INSERT INTO Test2 (Name, Value) VALUES('Name4', 5);
INSERT INTO Test2 (Name, Value) VALUES('Name5', 6);
INSERT INTO Test2 (Name, Value) VALUES('Name6', 7);
INSERT INTO Test2 (Name, Value) VALUES('Name7', 8);
-- suppose Name is unique
SELECT * FROM Test1 JOIN Test2 ON Test1.Name = Test2.Name
WHERE Test1.Value <> Test2.Value
But it's kinda uncomfortable solution, because I need to create really long queries for many columns... Any other idea?

When you use a natural join, the database will join using all columns that have the same name.
In this case, this will allow you to compare entire records.
Then, using an outer join, you can find out which records do not have a matching record in the other table:
SELECT Table1.ID
FROM Table1 NATURAL LEFT JOIN Table2
WHERE Table2.ID IS NULL

Related

How can I get rows from a table that matches all the foreign keys from another table

Say I have two tables role and roleApp defined like this:
create table #tempRole(roleId int);
insert into #tempRole (roleId) values (1)
insert into #tempRole (roleId) values (2)
create table #tempRoleApp(roleId int, appId int);
insert into #tempRoleApp (roleId, appId) values (1, 26)
insert into #tempRoleApp (roleId, appId) values (2, 26)
insert into #tempRoleApp (roleId, appId) values (1, 27)
So, from #tempRoleApp table, I want to get only the rows that matches all the values of the #tempRole table (1 and 2), so in this case the output needs to be 26 (as it matches both 1 and 2) but not 27 as the table does not have 2, 27).
#tempRole table is actually the output from another query so it can have arbitrary number of values.
I tried few things like:
select *
from #tempRoleApp
where roleId = ALL(select roleId FROM #tempRole)
Which does not give anything... tried few more things but not getting what I want.
I believe this gives what you were looking for.
select tra.appId
from #tempRoleApp as tra
join #tempRole as tr on tra.roleId = tr.roleId
group by tra.appId
having count(distinct tra.roleId) = (select count(distinct roleId) from #tempRole)
It uses count distinct to get the total unique roleId's in the tempRole table and compares that with the unique count of these per appId, after confirming the roleIds match between the tables.
As you clarified in the comment, once you add another tempRole roleId, now no entry has all of the Ids so no rows are returned.

Insert only non null values into SQL table

I try to insert values into my table, but I want to only insert the non null ones, the null values I need to just ignore no treatment needed. The variable I want to insert is a result of a SQL select, I tried this but it didn't work:
insert into mytable(id)
values (case when (select id from tab2 where login=?) is not null then (select id from tab2 where login=?))
In other words, I want to insert the id's that correspond to this condition and that are not null only.
here is how you can do it :
insert into mytable(id)
select id from tab2
where login=? and id is not null
You can try this one and see if that works for you:
insert into mytable(id)
select ID
from tab2
where id IS NOT NULL
and login = ?

SQL - SQL statement has been terminated if one insert into row is incorrect

I'm trying to insert hundreds of rows into a table using a query like:
Insert INTO tableX (column1, colum2)
VALUES
((SELECT sysID FROM tableY where ID = var1), 1)
((SELECT sysID FROM tableY where ID = var2), 1)
et cetera
Now let's say var88 doesn't exist, it will return NULL as sysID, however I can't insert a NULL into column1 so I get an error and the whole insert into query will be terminated. Is there a way to cancel the whole termination and just skip the rows where sysID = NULL? I'm sure I can do this by first doing a proper select, filtering out the NULL rows and THEN do the insert into, however I'm wondering if there is an other way to do this.
You can use the following instead, using a INSERT INTO SELECT:
INSERT INTO tableX (column1, colum2)
SELECT sysID, 1
FROM tableY
WHERE ID IN (va1, var2) AND NOT sysID IS NULL
Where/how are you getting the var1 (etc) variables for your values?
You can convert this to:
Insert INTO tableX (column1, colum2)
VALUES
Select SELECT sysID, 1
Where ID IN (var1, var2, etc..)
WHERE sysID is not null
Or build this into a loop somehow (depending on where/how your var1 etc are coming from

Insert data in multiple tables at a time with repeated values

I have to insert data into first and second table directly. But the third table which I received data as array and inserted into 3rd table as same.
In my 3rd table values will be repeated. Ex:
values:
{name=ff,age=45,empid=23,desig=se,offid=1,details=kk,offid=2,details=aa,offid=3,details=bb,offid=4,details=cc}
So using 2nd table userid as same for all the offid, but details and other columns are different
#My issue is i will get single hit but i need to iterate for 3rd table.
with first_insert as (
insert into sample(name,age)
values(?,?)
RETURNING id
),
second_insert as (
insert into sample1(empid,desig)
values((select id from first_insert),?)
RETURNING userid
)
insert into sample2(offid,details)
values((select userid from second_insert),?)
Is this available or possible in PostgreSQL?
Yes, absolutely possible.
You can join rows from CTEs to VALUES expressions to combine them for a new INSERT in a data-modifying CTE. Something like this:
WITH first_insert AS (
INSERT INTO sample(name,age)
VALUES (?,?)
RETURNING id
)
, second_insert AS (
INSERT INTO sample1(empid, desig, colx)
SELECT i1.id, v.desig, v.colx
FROM first_insert i1
, (VALUES(?,?)) AS v(desig, colx)
RETURNING userid
)
INSERT INTO sample2(offid, details, col2, ...)
SELECT i2.userid, v.details, ...
FROM second_insert i2
, (VALUES (?,?, ...)) AS v(details, col2, ...);

Adding a custom column to SQL query

Lets say I have a DB built like this:
NUM VALUE
1 3.51
2 hello
1 3.487
2 goodbye
1 32.4
2 foo
what I need to do to add another column in which all the values having num "2" will be in.
e.g.
NUM VALUE value2
1 3.51 hello
1 3.487 goodbye
1 32.4 foo
any idea how I can do this?
thanks!
In this example I am using SQLite, where the table Source already has a built-in rowid. Depending on the database you are using, you may need to add your own auto-incrementing integer column (i.e., integer primary key), but the idea is the same.
CREATE TABLE Source (num, value);
INSERT INTO Source (num, value) VALUES (1, 3.51);
INSERT INTO Source (num, value) VALUES (2, 'hello');
INSERT INTO Source (num, value) VALUES (1, 3.487);
INSERT INTO Source (num, value) VALUES (2, 'goodbye');
INSERT INTO Source (num, value) VALUES (1, 32.4);
INSERT INTO Source (num, value) VALUES (2, 'foo');
"1","3.51"
"2","hello"
"1","3.487"
"2","goodbye"
"1","32.4"
"2","foo"
SELECT a.num, a.value, b.value
FROM Source a
INNER JOIN Source b ON a.rowid = b.rowid - 1
WHERE a.num = 1 AND b.num = 2
"1","3.51","hello"
"1","3.487","goodbye"
"1","32.4","foo"