简体   繁体   中英

MS Access query to filter duplicates with criteria

I have 2 tables, 1Poolwaitingexchange and VA05(ZRAX) as shown in the link below.

http://i.stack.imgur.com/FN9tM.png

I need [Vcat] from VA05(ZRAX) and the relationship between the 2 tables is from both [Material Code]->[Description1] and [Cust PO] -> [PO Number] (also show in link)

The only issue is, for every [Material Code] & [Cust PO], there might be duplicates with different [Vcat] meaning all the fields are the same except for [Vcat] and I want the record with the lowest Vcat but not zero.

Eg. If the duplicate records have [Vcat] 0, 1, 2, 3, I want to choose the record that shows [Vcat] as 1.

If the records only have [Vcat] 0, I want it to show the record with [Vcat] as 0

and If [Vcat] is blank, return the record with [Vcat] blank.

The only unique record is the [Notif#] from table 1 and I have tried a lot of different approaches such as group by [Notif#], first for every duplicate field and MIN for [Vcat] but i just can't get the values i want.

My SQL knowledge is non-existant and I do a lot of trial and error I hope somebody can help me with this issue.

You have three cases which you can UNION together. Someone would be able no doubt to come up with a single SELECT that does all three with IFF s and OR s but you might find the UNION approach easier to follow, especially if you don't know SQL.

I've changed some names for my own convenience and I have used -999 because I avoid nulls:

SELECT p.Material_Code, p.Cust_PO, 1 AS VCat
  FROM Pool p
 WHERE EXISTS ( SELECT *
                  FROM VARAX v
                 WHERE v.Material_Code = p.Material_Code
                       AND v.Cust_PO = p.Cust_PO
                       AND v.Vcat > 0 )
UNION
SELECT p.Material_Code, p.Cust_PO, 0 AS VCat
  FROM Pool p
 WHERE EXISTS ( SELECT *
                  FROM VARAX v
                 WHERE v.Material_Code = p.Material_Code
                       AND v.Cust_PO = p.Cust_PO
                       AND v.Vcat = 0 )
       AND NOT EXISTS ( SELECT *
                          FROM VARAX v
                         WHERE v.Material_Code = p.Material_Code
                               AND v.Cust_PO = p.Cust_PO
                               AND v.Vcat > 0 )
UNION
SELECT p.Material_Code, p.Cust_PO, -999 AS VCat
  FROM Pool p
 WHERE NOT EXISTS ( SELECT *
                    FROM VARAX v
                   WHERE v.Material_Code = p.Material_Code
                         AND v.Cust_PO = p.Cust_PO );

Sounds to me like you want something like this. Unfortunately I don't have the ability to test my Access syntax at the moment. (I'm also assuming that "blank" is actually null. Please clarify the datatype of Vcat if not.)

select
    pwe.[Cust PO], pwe.[Part Number],
    switch(
        not isnull(min(switch(Vcat between 1 and 3, Vcat))),
          min(switch(Vcat between 1 and 3, Vcat))
        min(Vcat) = 0, 0,  true, null
    ) as Vcat
from
   1Poolwaitingexchange as pwe inner join VA05 as va
       on va.[PO Number] = pwe.[Cust PO] and va.Description = pwe.[Part Number]
group by pwe.[Cust PO], pwe.[Part Number]

You're right that my logic was originally bad. A minimum of zero was always going to supercede the legit values between 1 and 3. The modified version handles that by using logic that treats values outside that range as nulls and so they can be disregarded by the min aggregate.

You could get away with the slightly shorter versions below. All three share a common English interpretation: "Is there a value between 1 and 3? Then return the smallest one." I think the latter two read better but I don't know if you'll ever add other values that could break them. Since I don't know the nature of Vcat s and how they might change, I'll leave that to you.

    switch(
        max(Vcat) > 0, min(switch(Vcat between 1 and 3, Vcat))
        min(Vcat) = 0, 0,
        true, null
    ) as Vcat

    switch(
        max(Vcat) between 1 and 3, min(switch(Vcat between 1 and 3, Vcat))
        min(Vcat) = 0, 0,
        true, null
    ) as Vcat

Instead of joining with VA05(ZRAX) directly, try joining on query results of the rows in VA05(ZRAX) grouped the way you want. You can do that with two subqueries grouping for the min value with and without the zeroes.

So you'll have another query named qry_va05zrax_toPool_min as

select 
[po number], description, 
vcatmin:min(vcat)
from VA05(ZRAX)
group by 
[po number],description

and qry_va05zrax_toPool_minGT0:

select 
[po number], description, 
vcatminGT0:min(vcat)
from VA05(ZRAX)
group by 
[po number],description
having vcat > 0

and a third one on both of those like:

select
[po number], description, vcatVal:iif(vcatminGT0 is not null, vcatminGT0,iif(vcatmin is not null, 0, null) )
from
1poolWaitingExchange p left outer join
qry_va05zrax_toPool_min m on
p.[po number] = m.[po number] and
p.description = m.description left outer join
qry_va05zrax_toPool_minGT0 z on
p.[po number] = z.[po number] and
p.description = z.description

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM