Access SQL FROM IN and JOINS - sql

I've been successfully using
SELECT [field] FROM [Table] IN 'Network Location';
this question filled me in on that
Access SQL Query from another DB
My question is: How does a JOIN fit into this framework
Is it
SELECT [field]
FROM [Table] IN 'Network Location'
JOIN [Table2]
ON [Table2].field = [Table].field;
or
SELECT [field]
FROM [Table]
JOIN [Table2]
ON [Table2].field = [Table].field IN 'Network Location' ;
it feels like the former is the correct one. SQL statements are supposed to be like sentences and that one feels most appropriately ordered.

Consider the bracketed or backticked name qualifier to query from external Access databases. Semantically, this would follow other RBDMS' (e.g., Oracle, Postgres, SQL Server, MySQL, SQLite) period qualifiers to query across clusters, schemas, databases on same machine/server. From there use table aliases for referencing in SELECT, JOIN, WHERE, and other clauses.
SELECT t1.[field]
FROM [C:\Path\To\External\myDatabase.accdb].[Table] t1
INNER JOIN [Table2] t2
ON t2.field = t1.field;
SELECT t1.`field`
FROM `C:\Path\To\External\myDatabase.accdb`.`Table` t1
INNER JOIN `Table2` t2
ON t2.field = t1.field;
Do note, Access requires JOIN to be specific: INNER, LEFT, RIGHT.
And thanks to the JET/ACE SQL engine, you can even query Excel workbooks and CSV files in similar manner assuming data is contiguous in a table-like range:
SELECT *
FROM [Excel 12.0 Xml;HDR=Yes;Database=C:\Path\To\myWorkbook.xlsx].[SheetName$] AS t;
SELECT t.*
FROM [text;database=C:\Path\To\Folder].myFile.csv AS t;

Related

How to run the subquery first in presto

I have the following query:
select *
from Table1
where NUMid in (select NUMid
from Table2
where email = 'xyz#gmail.com')
My intention is to get the list of all the NUMids from table2 having an email value equal to xyz#gmail.com and use those list of NUMids to query from Table1.
In presto, the query is running the outer query first. Is there a way to run and store the result of inner query and then use it in the outer query in presto?
The optimizer can do what it likes. In this case, it should be running the inner query once and then essentially doing a JOIN (technically a "semi-join") operation.
In many databases, exists with appropriate indexes solves the performance problem.
If you want to ensure that the subquery is evaluated only once, you can move it to the ON clause. The correct equivalent query looks like:
select t1.*
from Table1 t1 join
(select distinct t2.NUMid
from Table2 t2
where t2.email = 'xyz#gmail.com'
) t2
on t1.NUMid = t2.NUMid;
The select distinct is important for the join code to be equivalent to the in code. However, if you know there are no duplicates, this is more colloquially written without a subquery:
select t1.*
from Table1 t1 join
Table2 t2
on t1.NUMid = t2.NUMid
where t2.email = 'xyz#gmail.com'
Presto and Trino (formerly known as PrestoSQL) execute that query as a "semi join" operation: it builds an in-memory index with the rows coming from the inner query and probes the rows of the outer query against that index. If value is present, the row from the outer query is emitted, otherwise, it's filtered out.
In recent versions of Trino, there's a feature called "dynamic filtering", which allows the query engine to dynamically filter and prune data for the outer query at the source based on information obtained dynamically from the inner query. You can read more about it in these blog posts:
Dynamic filtering for highly-selective join optimization
Dynamic partition pruning

Convert multiple SQL code with multiple subqueries into a single query

I'm starting to handle an old database that was generated years ago with ACCESS. All the queries have been designed with the ACCESS query wizard and they seem to be very time consuming and I would like to improve their performance.
All queries depend on at least three subqueries and I would like to rewrite the SQL code to convert them into a single query.
Here you have an example of what I'm talking about:
This is the main query:
SELECT Subquery1.pid, Table4.SIB, Subquery1.event,
Subquery1.event_date, Subquery2.GGG, Subquery3.status FROM Subquery1
LEFT JOIN ((Table4 LEFT JOIN Subquery2 ON Table4.SIB =
Subquery2.SIB) LEFT JOIN Subquery3 ON Table4.SIB = Subquery3.SIB)
ON Subquery1.pid = Table4.PID;
This main query depends on three subqueries:
Subquery1
SELECT Table2.id, Table2.pid, Table2.npid, Table3.event_date,
Table3.event, Table3.notes, Table2.other FROM Table2 INNER JOIN Table3
ON Table2.id = Table3.subject_id WHERE (((Table2.pid) Is Not Null) AND
((Table3.event_date)>#XX/XX/XXXX#) AND ((Table3.event) Like "*AAAA" Or
(Table3.event)="BBBB")) ORDER BY Table2.pid, Table3.event_date DESC;
Subquery2
SELECT Table1.SIB, IIf(Table1.GGG Like "AAA","BBB", IIf(Table1.GGG
Like "CCC","BBB", IIf(Table1.GGG Like "DDD","DDD","EEE"))) AS GGG FROM
Table1;
Subquery3
SELECT Table5.SIB, Table5.PID, IIf(Table5.field1 Like
"1","ZZZ",IIf(Table5.field1 Like "2","ZZZ",IIf(Table5.field1 Like
"3","ZZZ",IIf(Table5.field1 Like "4","HHH",IIf(Table5.field1 Like
"5","HHH",IIf(Table5.field1 Like "6","HHH","UUU")))))) AS SSS FROM
Table5;
Which would be the best way of improving the performance of this query and converting all the subqueries into a single statement?
I can handle each subquery, but I'm having a hard time joining them together.
If this:
Table5.field1 Like "3"
is really how some of your subqueries are written (without actual wild characters) you can save a lot of time by changing it to
Table5.field1="3"
'''you can create transient tables for each sub query'''
CREATE Transient table1 AS
'''Your sub query goes here'''
CREATE Transient table2 AS
'''Your sub query goes here'''
'''Main query to merge them into one'''
SELECT '''column names'''
FROM
table1
LEFT JOIN table2
ON table1.common_column = table2.common_column
LEFT JOIN table3
ON table1.common_column = table3.common_column
'''similarly you can combine all sub queries/transient tables'''

Select all fields from table A but single field from B?

Is there a way in ABAP's OpenSQL to simplify the select columns in a JOIN when I want to grab all the fields of one table but only selected fields from the other table(s)?
For instance, in mysql we can simply do:
SELECT tb1.*, tb2.b, tb2.d
FROM tableA tb1
INNER JOIN tableB tb2 ON tb1.x = tb2.a
However, OpenSQL does not seem to allow selecting tb1~*, tb2~b, tb2~d so I have to resort to this:
SELECT tb1.x, tb1.y, tb1.z, tb2.b, tb2.d
FROM tableA tb1
INNER JOIN tableB tb2 ON tb1.x = tb2.a
For very large tables, especially standard tables, this becomes unwieldy, difficult to read and more annoying to maintain.
Is there a better way to select all fields of tb1 and some fields from tb2?
Yes, this is possible in the OpenSQL from 7.40 SP08. See this article.
The quotation from the article has that.
Column Specification
In the SELECT list, you can specify all columns of a data source using the syntax data_source~* from 7.40, SP08 on. This can be handy when working with joins.
SELECT scarr~carrname, spfli~*, scarr~url
FROM scarr INNER JOIN spfli ON scarr~carrid = spfli~carrid
INTO TABLE #DATA(result).
In the previous versions unfortunately one has to specify the columns one by one or use database native SQL for example with ADBC.

Select from 2 tables with a left join

Here is probably an easy one if your used to SQL, which I'm not.
I have this query:
SELECT *
FROM myTable
LEFT JOIN anotherTable
ON myTable.myField=anotherTable.anotherField
Actually, this query returns everything from myTable which meets the join condition (as far as my comprehension goes). This query works great, but I would like to select another field from another table. What I would like to do is something like this:
SELECT myTable.*, myTable2.aSpecificField
FROM myTable, myTable2
LEFT JOIN anotherTable
ON myTable.myField=anotherTable.anotherField
WHERE myTable.id = myTable2.id
However, this doesn't work, I get an error message about the LEFT JOIN. I would like the aSpecificField from myTable2 to be added to the rows where the ID of both tables match.
Can you help me building this query correctly? Thank you.
The Microsoft Access query design window lets you use wizards or drag-and-drop to create queries. You can then tidy up the SQL in design view. Add your tables to the design grid, drag the joining fields from one table to the next, and then select the fields you want.
When you wish to advance your knowledge of Access SQL, you can read ...
These are for Jet (<2007), but ACE (>=2007) is not that different as regards SQL
Fundamental Microsoft Jet SQL for Access 2000
Intermediate Microsoft Jet SQL for Access 2000
Advanced Microsoft Jet SQL for Access 2000
Jet Database Engine
Background on design
Fundamentals of Relational Database Design, Paul Litwin, 2003
An often recommended MS Access book
Access cookbook
List out your fields rather then using *. Like so:
SELECT m.Field1, m.Field2, m2.Field1 FROM
MyTable m LEFT JOIN MyTable2 m2 ON m2.ID=m1.ID
Per your comment what relation does table3 have with another table?
Just include it based on that relationship
SELECT m.Field1, m.Field2, m2.Field1, m3.Field1 FROM
MyTable m LEFT JOIN MyTable2 m2 ON m2.ID=m1.ID LEFT JOIN MyTable3 m3 ON m3.ID=m2.ID
So you want to return the rows where the ids match for both tables? And not where they dont match? So not a left or right join but a plain join?
Select tab1.*,tab2.* from mytable tab1
INNER JOIN mytable2 tab2
ON tab1.id = tab2.otherid
Or if you have 3 tables to join?
Select tab1.*,tab2.*,tab3.* from mytable tab1
INNER JOIN mytable2 tab2
ON tab1.id = tab2.otherid
INNER JOIN mytable3 tab3
ON tab1.id = tab3.anotherid
Replace tabX.* with specific fields if needed?

NESTED INNER JOIN using MS Access 2003 via ODBC

If this works:
SELECT COUNT(t1.ID) AS count FROM Project t1
INNER JOIN (SELECT DISTINCT t.Site,t.id FROM _Equipment_id t WHERE t.OEM LIKE '%ABC%') t2 ON t1.Site=t2.Site AND t1.id=t2.id
and this works:
SELECT COUNT(t3.ID) AS count FROM Wall t3
INNER JOIN Project t1 ON t3.Project_number=t1.Project_number
Why doesn't this work:
SELECT COUNT(t3.ID) AS count FROM Wall t3
INNER JOIN Project t1 ON t3.Project_number=t1.Project_number
INNER JOIN (SELECT DISTINCT t.Site,t.id FROM _Equipment_id t WHERE t.OEM LIKE '%ABC%') t2 ON t1.Site=t2.Site AND t1.id=t2.id
Ultimately, I have 10 tables like the Wall table that I am trying to get a total count from the first SELECT....
SELECT COUNT(t3.ID) AS count FROM Wall t3
INNER JOIN (Project t1
INNER JOIN (SELECT DISTINCT t.Site,t.id FROM _Equipment_id t WHERE t.OEM LIKE '%ABC%') t2
ON t1.Site=t2.Site AND t1.id=t2.id)
ON t3.Project_number=t1.Project_number
Maybe it's just a syntax error? Office Help at the bottom where they mention nesting. The other possibility is that the aliases are somehow scoped so that they are not available to the join, but I'm no expert on MS Access. Maybe you should just try dropping the aliases altogether.
You have a couple of minor issues with your code: a table name that starts with an underscore character (_Equipment_id) and an AS clause ("alias") that is a SQL keyword (AS count). When these are corrected, your SQL is valid SQL-92 syntax.
Sadly, the problem is that Access (ACE, Jet, whatever) does not support the SQL-92 Standard. Access insists that each nested JOIN clause is put in parentheses.
[Aside: JOINs in parentheses are allowed in Standard SQL because it can potentially change the query results. However Access, does not respect the order specified by the coder and allows itself to evaluate JOINs in order it sees fir. So not only Access's syntax non-compliant with the Standard, there is also a loss of functionality! However, this further problem with Access will have no ill effect for this particular query.]
You have two JOINs in the same scope here:
...
INNER JOIN Project t1 ON t3.Project_number=t1.Project_number
INNER JOIN
...
Your code needs to work around Access's problem by enclosing the JOIN in parentheses; because all your JOINs are INNER flavour, it probably doesn't matter where they go.
Also, as regards correcting your AS clause, Access again doesn't support Standard SQL's quoted identifiers (...AS "count"...) and insists you use its proprietary square brackets syntax (...AS [count]...) -- of course, you could choose a different name but there may exist application code that relies on it.
Code to workaround both Access problems:
SELECT COUNT(t3.ID) AS [count]
FROM (Wall t3
INNER JOIN Project AS t1
ON t3.Project_number = t1.Project_number)
INNER JOIN (
SELECT DISTINCT t.Site,t.id
FROM _Equipment_id AS t
WHERE t.OEM LIKE '%ABC%'
) AS t2
ON t1.Site = t2.Site
AND t1.id = t2.id;