How can I implement SQL INTERSECT and MINUS operations in MS Access
INTERSECT is an inner join. MINUS is an outer join, where you choose only the records that don't exist in the other table.
INTERSECT
select distinct
a.*
from
a
inner join b on a.id = b.id
MINUS
select distinct
a.*
from
a
left outer join b on a.id = b.id
where
b.id is null
If you edit your original question and post some sample data then an example can be given.
EDIT: Forgot to add in the distinct to the queries.
How to INTERSECT in MS Access?
For test data in a table named [MirrorTest]
pk A B
-- ----- -----
1 foo bar
2 hello world
3 hello there
4 world hello
5 bar baz
6 bar foo
the query
SELECT pk, A, B
FROM MirrorTest
WHERE A<=B
UNION ALL
SELECT pk, B, A
FROM MirrorTest
WHERE A>B
will return all of the rows such that A<=B, i.e.,
pk A B
-- ----- -----
2 hello world
3 hello there
5 bar baz
6 bar foo
1 bar foo
4 hello world
Wrap that in an aggregation query to find the candidates for deletion, defined as the larger [pk] value where there are duplicates
SELECT Max(pk) AS pkToDelete
FROM
(
SELECT pk, A, B
FROM MirrorTest
WHERE A<=B
UNION ALL
SELECT pk, B, A
FROM MirrorTest
WHERE A>B
) AS u
GROUP BY A, B
HAVING COUNT(*) > 1
returns
pkToDelete
----------
6
4
so you could just use that in the WHERE clause of a DELETE query
DELETE FROM MirrorTest
WHERE pk IN
(
SELECT Max(pk) AS pkToDelete
FROM
(
SELECT pk, A, B
FROM MirrorTest
WHERE A<=B
UNION ALL
SELECT pk, B, A
FROM MirrorTest
WHERE A>B
) AS u
GROUP BY A, B
HAVING COUNT(*) > 1
)
Minus Query in MsAccess
One possibility is NOT IN. There is no such thing as a minus query in MS Access.
select h.* from hello h
WHERE uniqueid NOT IN
(select uniqueid from hello1 h1)
For a purely sql solution, you need, say:
SELECT t.* FROM Table t
LEFT JOIN NewTable n
ON t.ID = n.ID
WHERE t.Field1 & "" <> n.Field1 & ""
OR t.Field2 & "" <> n.Field2 & ""
However, it is easier using VBA.
Implementing INTERSECT (INNER JOIN) in MS ACCESS
Haven't tested this so definitely you will have a lot of MS Access specific changes to be made. But I ask you not to obfuscate query by unnecessarily quoting each identifier in square blocks:
SELECT DISTINCT title
FROM (
SELECT [Catt].[Name] as title
FROM [Catt]
WHERE ([Catt].[Name] Like "*" & [forms]![Main]![SrchText] & "*") AND
[forms]![Main]![SrchText] IS NOT Null AND
[forms]![Main]![SrchText] <>''
) AS view1
INNER JOIN
(
SELECT [Catt].[Name]
FROM [Catt]
WHERE [Catt].[Category] Like [forms]![Main]![Combo7].Value AND
([forms]![Main]![SrchText] IS Null OR
[forms]![Main]![SrchText]='')
) AS view2 ON view1.title = view2.Name
ORDER BY view1.title
But basically something like this does the trick..
Edited as Gordon pointed out
Subtracting Lists from Queries in Access
One method uses not in
or not exists
. Assuming that column A
is unique, you can do:
select s.*
from (<Suche>) as s
where s.A not in (select d.a from (<DUN>) as d) and
s.A not in (select h2.a from (<HOL>) as h2);
problem with intersect operation in a sql query
What database are you using? Are you sure that intersect
is supported? I tried your query on Oracle (changing the table names to something corresponding to my DB) and it worked ok.
EDIT:
Since you confirmed you are using MS-Access, then it's clear that INTERSECT is the problem since it's not supported with MS-Access: http://www.access-programmers.co.uk/forums/archive/index.php/t-86531.html
EDIT2:
This is untested, but the basic idea is that you need to find all rows in your first query that exist in your second query. To do that, you will have to compare every column between the 2 queries for a match, as all the columns must match for it to be an "intersected" row.
There may be some syntax issues, but hopefully this gets you started.
SELECT r.col1
, t.col1
/* list all other columns here */
FROM results r
, types t
WHERE r.a = t.b
AND EXISTS (
SELECT *
FROM results r2
, types t2
WHERE r2.c = t2.b
AND NZ(r.col1,0) = NZ(r2.col1,0)
AND NZ(t.col1,0) = NZ(t2.col1,0)
/* list other columns here, they all need to match so intersection will work */
)
Ms Access - show difference between two query results
This would be much easier if Access implemented all of the ISO SQL set operators (UNION, INTERSECTION, REMOVE) because what you want is the REMOVE operation (called MINUS in Oracle). However, like MySql MS-Access only implements the UNION operator. Fortunately, MySql has a doc page that explains how to implement the MINUS (REMOVE) operator functionality in SQL without the keyword
As it happens, you got pretty close, you just need to add an extra set of conditions to your NOT EXISTS query.
So something like this should work:
SELECT AllMFR.*
FROM AllMFR
WHERE NOT EXISTS(
SELECT *
FROM UniqueMFR
WHERE UniqueMFR.ITEM_NUMBER = AllMFR.ITEM_NUMBER
AND UniqueMFR.MFR = AllMFR.MFR
AND UniqueMFR.MFR_PN = AllMFR.MFR_PN
);
Minus/hyphen in table name in SQL query
Access automatically interprets a word break before -
This means:
SELECT * from MYTAB-10
Is equivalent to the following queries
SELECT * FROM MYTAB -10 -- Space added
SELECT * from [MYTAB] AS [-10] -- Explicit alias to make meaning more clear
This also means you could write the following
SELECT [-10].SomeField FROM MYTAB-10 INNER JOIN MYTAB-11 ON [-10].SomeField = [-11].AnotherField
As ADO automatically adds SELECT * FROM
if you just provide a table name, that's equivalent.
However: NEVER use this. This behavior hasn't been standardized, and will make your code nonportable as other RDBMSes will syntax error on it.
Also note that this doesn't work in ADO when directly opening a table instead of using an auto-generated SQL statement:
Set rst = CurrentProject.Connection.Execute("MYTAB-10", Options := adCmdTableDirect)
'Errors: cannot find input table or query MYTAB-10
Also note: the +
character exhibits similar behavior. However, \
, :
and *
do not.
Writing a difficult query for MS-Access (without MINUS operation, 3 table join)
The query below is created from two MS Access queries with the SQL cut and pasted into derived tables. The two queries select the employee with their current training (#1) and the employee with their required training (#2). It is not updateable, but is easy to create. You can show only the missing training by adding a line at the end:
WHERE et.TrainingName Is Null
To select a single employee, you can add a line:
WHERE rt.EMPID=1 AND et.TrainingName Is Null
However, you mention a subform, so I expect you will wish to use link child and master fields to limit by employee.
SQL
SELECT rt.empid,
rt.position,
rt.trainingname,
et.trainingname AS IsTrained
FROM (SELECT employees.empid,
requiredtraining.position,
requiredtraining.trainingname
FROM employees
INNER JOIN requiredtraining
ON employees.position = requiredtraining.position) AS rt
LEFT JOIN (SELECT employees.empid,
employees.position,
employeetraining.trainingname
FROM employees
INNER JOIN employeetraining
ON employees.empid = employeetraining.empid) AS
et
ON ( rt.trainingname = et.trainingname )
AND ( rt.position = et.position )
AND ( rt.empid = et.empid );
Related Topics
Get Everything After and Before Certain Character in SQL Server
SQL Server Cumulative Sum by Group
Finding a Top Level Parent in SQL
How to Handle Optional Parameters in SQL Query
How to Create a Decimal Field in Access with Alter Table
Create Postgresql Role (User) If It Doesn't Exist
Select Rows with Same Id But Different Value in Another Column
How to Work with SQL Null Values and JSON in a Good Way
Prevent Duplicate Values in Left Join
How to Select Records Without Duplicate on Just One Field in SQL
Partition by with and Without Keep in Oracle
Combinations (Not Permutations) from Cross Join in SQL
Opinions on Sensor/Reading/Alert Database Design
Concurrency Handling of SQL Transactrion
Is Id Column Position in Postgresql Important
How to Report an Error from a SQL Server User-Defined Function