Combining tables in SQLITE while directly replacing values from another table - sqlite

I have a sqlite db with 4 tables. I now want to retrieve the contents of one of them and replace the contents of one of its rows with the respective content of one of the other tables and then return the result.
E.g.
Table 1:
Row0, Row1, Row2, ..., Row20
'some numbers' 'some numbers' 'name string' .... 'some numbers'
Table 2:
Row0, Row1
'name string' 'name (cleaned and formatted)'
So every time I access a row in table 1 instead of returning the value for Table1.Row2 it should return my the corresponding value of Table2.Row1 if there is no such value then just use the existing one from Table1.Row2
Just using
select * from table1 inner join row2 on table1.row2 = table2.row0 doesn't work.
If this question has already been answered, I'm happy to head over to the post, yet I have no clue on how to search for my problem, which is why I'm writing it here.
Thanks
Liz

Related

Apex Collection: how to have actual column names instead of C001, C002

created a page to allow users to input SQL statement, when user press button, it should Execute this query and another region with Classic Report will display results.
on Button a Dynamic Action execute PL/SQL code below:
on Click event:
begin
IF :P8_YOURSQL IS NOT NULL THEN
APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY (
p_collection_name => 'SOMECOLLECTION',
p_query => :P8_YOURSQL,
p_truncate_if_exists => 'YES'
);
end if;
end;
Item to Submit: P8_YOURSQL
second Action refreshes CR region and CR region is based on:
SELECT * FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = 'SOMECOLLECTION';
resulted columns are not limited to the query results and column headers are C001, C002, C003 etc.
(a) how i can limit the columns to the SQL statement contained?
(b) how to change header to the actual column names?
(c) how to check for a valid SQL statement?
please help with sample code How To.
APEX_COLLECTIONS is a generic table so it has a couple of columns for the most common data types with names like C001, N001 etc. As with any table columns can be aliased in a query.
Example:
Create page process before header to populate the collection
APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY (
p_collection_name => 'EMP_COLLECTION',
p_query => q'!SELECT * FROM emp!',
p_truncate_if_exists => 'YES'
);
Run the page and open the "Session" window from the developer toolbar. Select "Collections" in the "View" dropdown and click "Set". This will list the data in the APEX_COLLECTIONS table for any collections that exist for the session. Take note of the data and the columns the data is in.
Leave the "Sessions" window open and create a sql query on the APEX_COLLECTIONS view with appropriate aliases.
SELECT
c001 as EMPNO,
c002 as ENAME,
c003 as JOB,
c004 as MGR,
<rest_of_columns>...
FROM
APEX_COLLECTIONS WHERE collection_name = 'EMP_COLLECTION'
It's not possible to alias columns when doing a SELECT * FROM ...
If the SELECT * is important then there is another possibility. Create a view on top of APEX_COLLECTIONS with relevant column names. Example:
CREATE OR REPLACE view EMP_COLLECTION_V
AS
SELECT
c001 as EMPNO,
c002 as ENAME,
c003 as JOB,
c004 as MGR
FROM
APEX_COLLECTIONS WHERE collection_name = 'EMP_COLLECTION'
and then use SELECT * FROM EMP_COLLECTION_V as SQL source for the classic report.
To get the columns names for a SELECT * FROM ... have a look at [DBMS_SQL.DESCRIBE_COLUMNS3][https://docs.oracle.com/en/database/oracle/oracle-database/18/arpls/DBMS_SQL.html#GUID-00AB5DE3-C428-4E60-9398-FD4892F32402]. There is an example in the doc that shows how to print the column names.
This can then be implemented in a classic report
Create a page item per column: P1_C1, P1_C2, etc
Set the column header for each column to the corresponding page item: col1 has header &P1_C1, col2 has header &P1_C2, etc
Create a page process to set the column headers based on the sql query using DBMS_SQL.DESCRIBE_COLUMNS3 - OR - use a
Note that it is strongly advised to assert the sql query to avoid unwanted sql (like a delete or drop table command).

Cheapest way to return if INSERTed new row

Let's say that I insert a record:
INSERT INTO table (pet1, pet2)
VALUES ('dog', 'cat')
WHERE NOT EXISTS
(SELECT 1 FROM table WHERE pet1='dog' AND pet2='cat);
What is the least expensive way to check if the statement actually affected a row?

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.

"Insert if not exists" statement in SQLite

I have an SQLite database. I am trying to insert values (users_id, lessoninfo_id) in table bookmarks, only if both do not exist before in a row.
INSERT INTO bookmarks(users_id,lessoninfo_id)
VALUES(
(SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
(SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+")
WHERE NOT EXISTS (
SELECT users_id,lessoninfo_id from bookmarks
WHERE users_id=(SELECT _id FROM Users
WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+")))
This gives an error saying:
db error near where syntax.
If you never want to have duplicates, you should declare this as a table constraint:
CREATE TABLE bookmarks(
users_id INTEGER,
lessoninfo_id INTEGER,
UNIQUE(users_id, lessoninfo_id)
);
(A primary key over both columns would have the same effect.)
It is then possible to tell the database that you want to silently ignore records that would violate such a constraint:
INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
If you have a table called memos that has two columns id and text you should be able to do like this:
INSERT INTO memos(id,text)
SELECT 5, 'text to insert'
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
If a record already contains a row where text is equal to 'text to insert' and id is equal to 5, then the insert operation will be ignored.
I don't know if this will work for your particular query, but perhaps it give you a hint on how to proceed.
I would advice that you instead design your table so that no duplicates are allowed as explained in #CLs answer below.
For a unique column, use this:
INSERT OR REPLACE INTO tableName (...) values(...);
For more information, see: sqlite.org/lang_insert
insert into bookmarks (users_id, lessoninfo_id)
select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;
This is the fastest way.
For some other SQL engines, you can use a Dummy table containing 1 record.
e.g:
select 1, 167 from ONE_RECORD_DUMMY_TABLE

MySQL Changing Order Depending On Contents of a Column

I have a MySQL table Page with 2 columns: PageID and OrderByMethod.
I also then have a Data table with lots of columns including PageID (the Page the data is on), DataName, and DataDate.
I want OrderByMethod to have one of three entries: Most Recent Data First, Most Recent Data Last, and Alphabetically.
Is there a way for me to tack an "ORDER BY" clause to the end of this query that will vary its ordering method based on the contents of the "OrderByMethod" column? For example, in this query, I would want to have the ORDER BY clause contain whatever ordering rule is stored in Page 1's OrderByMethod column.
GET * FROM `Data` WHERE `Data`.`PageID`=1 ORDER BY xxxxxx;
Maybe a SELECT clause in the ORDER BY clause? I'm not sure how that would work though.
Thanks!
select Data.*
from Data
inner join Page on (Data.PageID=Page.PageID)
where Data.PageID=1
order by
if(Page.OrderByMethod='Most Recent Data First', now()-DataDate,
if(Page.OrderByMethod='Most Recent Data Last', DataDate-now(), DataName)
);
You can probably do this with the IF syntax to generate a column that you can then order by.
SELECT *, IF(Page.OrderBy = 'Alphabetically', Data.DataName, IF(Page.OrderBy = 'Most Recent Data First', NOW() - Data.DataDate, Data.DataDate - NOW())) AS OrderColumn
FROM Data
INNER JOIN Page ON Data.PageID = Page.PageID
WHERE Page.PageID = 1
ORDER BY OrderColumn
The direction of the ordering is determined in the calculation of the data instead of specifying a direction in the ORDER BY
Can you just append the order by clause to the select statement and rebind the table on postback?
If you want to use the content of the column in Page table as an expression in ORDER BY you have to do it using prepared statements. Let say, you store in OrderByMethod something like "field1 DESC, field2 ASC" and you want this string to be used as it is:
SET #order_by =(SELECT OrderByMethod FROM Page WHERE id = [value]);
SET #qr = CONCAT(your original query,' ORDER BY ', #order_by);
PREPARE stmt FROM #qr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
If you want the result set to be sorted based on the value of OrderByMethod , you can use IF as it was already mentioned by others, or CASE :
...
ORDER BY
CASE OrderByMethod
WHEN 'val1' THEN field_name1
WHEN 'val2' THEN field_name2
....etc
END

Resources