Sqlite | How do I select records from two different tables using Case? - sqlite

Edit
I would rather explicitly state my problem I'm facing rather than assuming the approach. There could be an easiest solution to my problem.
I need to select records by joining two different table based on the result from another table. And I have to use different joins based on the result from the first table.
If a particular record is present in the first table, I have two use inner join the first table whereas if it's not present, then I have to left join.
bool recordPresent = select exists (select * from firstTable where access_id = 13) as access
if (recordPresent)
results = select * from secondTable s left join firstTable f on f.access_id = s.access_id where f.access_id is null order by access_id
else
results = select * from secondTable s inner join firstTable f on f.access_id = s.access_id

Related

In SQLite is there a way to test if two tables are identical?

Assume the two tables reside in the same file. So the question is, other than their names, are the tables identical, i.e., same schema, same contents.
To compare the table schemas, look at the statements in the sqlite_master table:
SELECT sql FROM sqlite_master WHERE tbl_name IN ('This', 'That');
You have to ignore the table name itself in the comparison; automatic replacement is harder if you have any column names or comments that containt the table name.
To compare the contents, just use compound queries to check whether there are any rows that are not in the other table:
SELECT NOT EXISTS (SELECT * FROM This
EXCEPT
SELECT * FROM That)
AND NOT EXISTS (SELECT * FROM That
EXCEPT
SELECT * FROM This);
I believe that the following may suffice :-
/*
Compare Schema and data in tables.
t1 is the SQL for the first table (mytable) with the table name changed to a common name (table)
t2 is the SQL for the second table (mytable_copy1) with the table changed to a common name (table)
(so if t1 and t2 are equal then the schema is the same)
tablecompare is the logical result of comparing the data of each table with the other table
except matching rows so if no rows exists then NOT EXISTS will be true (1) AND the two
and the result will be 1 if both tables exactly match each other.
*/
SELECT
(t1 = t1) AND tablecompare AS test FROM
(SELECT
replace(sql,'mytable','table') AS t1, -- change the table name to a common name
replace(sql,'mytable_copy1','table') AS t2, -- change the table name to a common name
(
SELECT NOT EXISTS (SELECT * FROM mytable EXCEPT SELECT * FROM mytable_copy1)
AND NOT EXISTS (SELECT * FROM mytable_copy1 EXCEPT SELECT * FROM mytable)
) AS tablecompare
FROM sqlite_master WHERE name = 'mytable'
)
Note the tables are mytable and mytable_copy1 so these would be changed to reflect the two tables.
Perhaps less confusing (perhaps more) is this more long-winded solution :-
/*
Table Compare
t1 is the SQL for the first table (mytable) with the table name replace by table
t2 is the SQL for the second table (mytable_copy1) again table name change to table
So if t1 = t2 then the schema is identical
t1count is the number of rows in the first table
t2count is the number of rows in the second table
So if the counts are the same then the tables may be identical
unioncount is the count of the union of the two tables (not union all) so duiplicates are dropped
therefore if unioncount is the same as either of the table counts then tables are identical
NOTE!!! this assumes tables are not WITHOUT ROWID tables (would have to omit the inclusion of rowid NOT TESTED)
the inclusion of rowid could be dropped (NOT TESTED) if there is an alias of rowid.
*/
SELECT
t1 = t1 AND t1count = t2count AND t1count = unioncount AS test FROM
(SELECT
replace(sql,'mytable','table') AS t1, -- change the table name to a common name
replace(sql,'mytable_copy1','table') AS t2, -- change the table name to a common name
(SELECT count() FROM mytable) AS t1count, -- get the number of rows
(SELECT count() FROM mytable_copy1) AS t2count, -- get the number of rows
(SELECT count() AS unioncount FROM
(SELECT rowid,* FROM mytable UNION SELECT rowid,* FROM mytable_copy1)) AS unioncount
FROM sqlite_master WHERE name = 'mytable'
) ;
Both solutions return a single row/column result 1 if the tables match 0 if they do not.
It could however, but less time consuming/resource hungry to do individual tests. e.g. if the schema's don't match do nothing otherwise check the row counts and if they don't match don't do the final check of actually checking the data.
Test the following tables were used for testing :-
For mytable and mytable_copy1 :-
The above both produced 1 as per :-
and :-
When the following table (mytable_copy2 with changed data highlighted) :-
The results were :-
and :-

Update row with value from next row sqlite

I have the following columns in a SQLite DB.
id,ts,origin,product,bid,ask,nextts
1,2016-10-18 20:20:54.733,SourceA,Dow,1.09812,1.0982,
2,2016-10-18 20:20:55.093,SourceB,Oil,7010.5,7011.5,
3,2016-10-18 20:20:55.149,SourceA,Dow,18159.0,18161.0,
How can I populate the 'next timestamp' column (nextts) with the next timestamp for the same product (ts), from the same source? I've been trying the following, but I can't seem to put a subquery in an UPDATE statement.
UPDATE TEST a SET nextts = (select ts
from TEST b
where b.id> a.id and a.origin = b.origin and a.product = b.product
order by id asc limit 1);
If I call this, I can display it, but I haven't found a way of updating the value yet.
select a.*,
(select ts
from TEST b
where b.id> a.id and a.origin = b.origin and a.product = b.product
order by id asc limit 1) as nextts
from TEST a
order by origin, a.id;
The problem is that you're using table alias for table in UPDATE statement, which is not allowed. You can skip alias from there and use unaliased (but table-name prefixed) reference to its columns (while keeping aliased references for the SELECT), like this:
UPDATE TEST
SET nextts = (
SELECT b.ts
FROM TEST b
WHERE b.id > TEST.id AND
TEST.origin = b.origin AND
TEST.product = b.product
ORDER BY b.id ASC
LIMIT 1
);
Prefixing unaliased column references with the table name is necessary for SQLite to identify that you're referencing to unaliased table. Otherwise the id column whould be understood as the id from the closest[*] possible data source, in which case it's the aliased table (as b alias), while we're interested in the unaliased table, therefore we need to explicitly tell SQLite that.
[*] Closest data source is the one listed in the same query, or parent query, or parent's parent query, etc. SQLite is looking for the first data source (going from inner part to the outside) in the query hierarchy that defines this column.

SQL update based on column in other table

Using SQLite, I am trying to update three columns based on another table (two columns)
The three columns are (Table1):
'AgentCreatedID'
'AgentOwnedID'
'AgentSentID'
The other table (Table2) consists of 'AgentID' and 'Designation'.
If the ID in one of the three columns matches the 'AgentID' in the second table, I want the 'Designation' value to populate. This table is a list of ALL unique IDs and the corresponding designation. Each row of data has a Creator, Owner, and Sender. I need to see what designation that person is from.
In Access, this would look something like this for the first value. I would also need to add the other two values.
UPDATE Table1
LEFT JOIN Table2 ON Table1.AgentCreatedID = Table2.AgentID
SET raw.AgentCreatedID = [ Table2 ]![ Designation];
I am not sure what that ! command is or how it could be used in SQLite.
SQLite does not suport joins in an UPDATE statement.
You have to look up the new value with correlated subqueries:
UPDATE Table1
SET AgentCreatedID = (SELECT Designation
FROM Table2
WHERE AgentID = AgentCreatedID),
AgentOwnedID = (SELECT Designation
FROM Table2
WHERE AgentID = AgentOwnedID),
AgentSentID = (SELECT Designation
FROM Table2
WHERE AgentID = AgentSentID)
The exclamation mark is used to separate the worksheet name from the reference in that worksheet. Here is Microsoft's explanation of cell references.
Now that you know what [ Table2 ]![Designatio] means, you can simplify it to use only the column name.

Sqlite double left outer join with count

I have the following DB structure:
tbl_record(_id,_id_user,...)
tbl_photo(_id,_id_record,...)
tbl_note(_id,_id_record,...)
When listing the records of a specific user while counting the number of photos a record has, I use the following query, which works fine:
SELECT tbl_record._id, COUNT(tbl_photo._id_record) AS photo_count FROM tbl_record
LEFT OUTER JOIN tbl_photo ON tbl_record._id=tbl_photo._id_record
WHERE tbl_record._id_user=? GROUP BY tbl_record._id;
Now, I'd like to do the same as above, but also count the number of notes a record has:
SELECT tbl_record._id, COUNT(tbl_photo._id_record) AS photo_count, COUNT(tbl_note._id_record) AS note_count FROM tbl_record
LEFT OUTER JOIN tbl_photo ON tbl_record._id=tbl_photo._id_record
LEFT OUTER JOIN tbl_note ON tbl_record._id=tbl_note._id_record
WHERE tbl_record._id_user=? GROUP BY tbl_record._id;
The count of the 2nd query does not work properly when a record has >0 photos & >0 notes, e.g. 3 photos & 5 photos which results in a count of 15 (3*5) for each.
Any idea how to make the 2nd query return the proper counts?
Thanks!!
You might be able to filter out duplicates by using COUNT(DISTINCT some_id), but this would be inefficient.
Better use correlated subqueries:
SELECT _id,
(SELECT COUNT(*)
FROM tbl_photo
WHERE _id_record = tbl_record._id
) AS photo_count,
(SELECT COUNT(*)
FROM tbl_note
WHERE _id_record = tbl_record._id
) AS note_count
FROM tbl_record
WHERE _id_user = ?

Sqlite Query replacing a column with a column from another table

I have 2 tables, one is indexing the other.
I am querying Table#1, and it has one column (string) that has an ID in it that corresponds to a unique row in Table#2. Im trying to write a query in Sqlite that allows me to retrieve the value from Table#2 if the column value in Table#1 is not an empty string.
Kinda like:
"SELECT TMake,TModel,TTrim,IYear,[%q] AS TPart1 FROM AppGuide WHERE TPart1 != ''"
But instead of retrieving the Index value (TPart1) Id like to get the string from Table#2.
Is this possible?
Any help is appreciated.
You could use a correlated subquery:
SELECT TMake,
TModel,
...,
(SELECT stringvalue
FROM Table2
WHERE Table2.ID = Table1.TPart1)
FROM Table1
WHERE Table1.TPart1 != ''
However, these are rather slow to execute, so you'd better use a join (this returns exactly the same result):
SELECT Table1.TMake,
Table1.TModel,
...,
Table2.stringvalue
FROM Table1 LEFT JOIN Table2 ON Table1.TPart1 = Table2.ID
WHERE Table1.TPart1 != ''
If you don't want to get records from Table1 that have no matching Table2 record, drop the LEFT.

Resources