Search code examples
ms-access-2016

MS Access: compare multiple query results from one table against the results of a query on the same table


I am building an ms access db to manage part numbers of mixtures. It’s pretty much a bill of materials. I have a table, tblMixtures that references itself in the PreMixture field. I set this up so that a mixture can be a pre-mixture in another mixture, which can in turn be a pre-mixture in another mixture, etc. Each PartNumber in tblMixture is related to many Components in tblMixtureComponents by the PartNumber. The Components and their associated data is stored in tblComponentData. I have put in example data in the tables below.

tblMixtures

PartNumber Description PreMixtures
1 Mixture 1 4, 5
2 Mixture 2 4, 6
3 Mixture 3
4 Mixture 4 3
5 Mixture 5
6 Mixture 6

tblMixtureComponents

ID PartNumber Component Concentration
1 1 A 20%
2 1 B 40%
3 1 C 40%
4 2 A 40%
5 2 B 30%
6 2 D 30%

tblComponentData

ID Name Density Category
1 A 1.5 O
2 B 2 F
3 C 2.5 I
4 D 1 F

I have built the queries needed to pull the information together for the final mixture and even display the details of the pre-mixtures and components used for each mixture. However, with literally tens of thousands of part numbers, there can be a lot of overlap in pre-mixtures used for mixtures. In other words, Mixture 4 can be used as a pre-mixture for Mixture 1 and Mixture 2 and a lot more. I want to build a query that will identify all possible mixtures that can be used as a pre-mixture in a selected mixture. So I want a list of all the mixtures that have the same components or subset of components as the selected mixtures. The pre-mixture doesn’t have to have all the components in the mixture, but it can’t have any components that are not in the mixture.


Solution

  • If you haven't solved it yet...

    The PreMixtures column storing a collection of data is a sign that you need to "Normalize" your database design a little more. If you are going to be getting premixture data from a query then you do not need to store this as table data. If you did, you would be forced to update the premix data every time your mixtures or components changed.

    Also we need to adress that tblMixtures doesn't have an id field. Consider the following table changes:

    tblMixture:

    id description
    1 Mixture 1
    2 Mixture 2
    3 Mixture 3

    tblMixtureComponent:

    id mixtureId componentId
    1 1 A
    2 1 B
    3 1 C
    4 2 A
    5 2 B
    6 2 D
    7 3 A
    8 4 B

    I personally like to use column naming that exposes primary to foreign key relationships. tblMixtures.id is clearly related to tblMixtureComponenets.mixtureId. I am lazy so i would also probably abreviate everything too.

    Now as far as the query, first lets get the components of mixture 1:

    SELECT tblMixtureComponent.mixtureId, tblMixtureComponent.componentId
    FROM tblMixtureComponent
    WHERE tblMixtureComponent.mixtureId = 1
    

    Should return:

    mixtureId componentId
    1 A
    1 B
    1 C

    We could change the WHERE clause to the id of any mixture we wanted. Next we need to get all the mixture ids with bad components. So we will build a join to compare around the last query:

    SELECT tblMixtureComponent.mixtureId
    FROM tblMixtureComponenet LEFT JOIN
        (SELECT tblMixtureComponent.mixtureId, 
        tblMixtureComponent.componentId
        FROM tblMixtureComponent
        WHERE tblMixtureComponent.mixtureId = 1) AS GoodComp
    ON tblMixtures.componentId = GoodComp.componentId
    WHERE GoodComp.componentId Is Null
    

    Should return:

    mixtureId
    2

    Great so now we have ids of all the mixtures we don't want. Lets add another join to get the inverse:

    SELECT tblMixture.id
    FROM tblMix LEFT JOIN
        (SELECT tblMixtureComponent.mixtureId
        FROM tblMixtureComponenet LEFT JOIN
            (SELECT tblMixtureComponent.mixtureId, 
            tblMixtureComponent.componentId
            FROM tblMixtureComponent
            WHERE tblMixtureComponent.mixtureId = 1) AS GoodComp
        ON tblMixtures.componentId = GoodComp.componentId
        WHERE GoodComp.componentId Is Null) AS BadMix
    ON tblMixtures.id = BadMix.mixtureId
    WHERE BadMix.mixtureId = Null AND tblMixture.id <> 1
    

    Should return:

    mixtureId
    3
    4

    Whats left is all of the ids of that have similar components but not nonsimilar components to mixture 1.

    Sorry i did this on a phone...