MS-Access: Finding records with multiple matching criteria - vba

I'm learning on the go and really appreciate any help you can give me.
I need to calculate a record's first appearance in my 'issue log' table.
Raw data is added to the table once per week. If an issue is resolved by the next run, it will be omitted, but if the issue is still there a new record will be appended into the table.
I need to populate a new column with when issue first appeared. The challenge is that if a record is omitted from the previous run, the counter 'resets'.
table example - records are added once per week (can take place on different days), record is a repeat if there is a match between certain fields (in this example "country" and "material") and the column that needs to be populated is the "first appearance" column.
Any help is appreciated! :)
Edit - just to clarify, I'm not looking for a code, just an idea on how to tackle this. I was thinking of adding the date for the previous report as an additional column, with a VB counting each consecutive appearance, but it seems like there might be an easier solution. Any ideas are welcome, Thanks!

Assuming that your screenshot is a representation of an Access table (Table1) then you need to SELECT the MINinimum date for each GROUP of Country & Material fields FROM Table1.
Try:
SELECT MIN(dDate) AS First_Appearance,
Country,
Material
FROM Table1
GROUP BY Country,
Material
ORDER BY MIN(dDate)
Edit:
Based on your example data you should only be showing Romania, Ukraine and Israel with material C as these are the only records that appear in the latest week (11/09/2016).
Israel only appears once, so that date is its first appearance.
Romania appears on the 11th and 28th. As it didn't appear on the 4th then the 11th is it's first appearance.
Ukraine appears on the 11th and 4th, so its first appearance is the 4th.
SELECT T1.dDate
, T1.Country
, T1.Material
, MIN(T2.dDate) AS First_Appearance
FROM Table1 T1 INNER JOIN Table1 T2 ON
T1.Country = T2.Country AND
T1.Material = T2.Material AND
(T2.dDate + 7 = T1.dDate or T2.dDate = T1.dDate)
WHERE T1.dDate = (SELECT MAX(dDate) FROM Table1)
GROUP BY T1.Country, T1.Material, T1.dDate
ORDER BY T1.Country, T1.Material
If you were to look at the previous week (change your WHERE clause to WHERE T1.dDate = #09/04/2016#) you'd get:
Dubai B with a first appearance of 28th.
Romania B with a first appearance of 4th.
Spain A with a first appearance of 28th.
Ukraine C with a first appearance of 4th.

Related

SAP BO - how to get 1/0 distinct values per week in each row

the problem I am trying to solve is having a SAP Business Objects query calculate a variable for me because calculating it in a large excel file crashes the process.
I am having a bunch of columns with daily/weekly data. I would like to get a "1" for the first instance of Name/Person/Certain Identificator within a single week and "0" for all the rest.
So for example if item "Glass" was sold 5 times in week 4 in this variable/column first sale will get "1" and next 4 sales will get "0". This will allow me to have the number of distinct items being sold in a particular week.
I am aware there are Count and Count distinct functions in Business Objects, however I would prefer to have this 1/0 system for the entire raw table of data because I am using it as a source for a whole dashboard and there are lots of metrics where distinct will be part/slicer for.
The way I doing it previously is with excel formula: =IF(SUMPRODUCT(($A$2:$A5000=$A2)*($G$2:$G5000=$G2))>1,0,1)
This does the trick and gives a "1" for the first instance of value in column G appearing in certain value range in column A ( column A is the week ) and gives "0" when the same value reappears for the same week value in column A. It will give "1" again when the week value change.
Since it is comparing 2 cells in each row for the entire columns of data as the data gets bigger this tends to crash.
I was so far unable to emulate this in Business Objects and I think I exhausted my abilities and googling.
Could anyone share their two cents on this please?
Assuming you have an object in the query that uniquely identifies a row, you can do this in a couple of simple steps.
Let's assume your query contains the following objects:
Sale ID
Name
Person
Sale Date
Week #
Price
etc.
You want to show a 1 for the first occurrence of each Name/Week #.
Step 1: Create a variable with the following definition. Let's call it [FirstOne]
=Min([Sale ID]) In ([Name];[Week #])
Step 2: In the report block, add a column with the following formula:
=If [FirstOne] = [Sale ID] Then 1 Else 0
This should produce a 1 in the row that represents the first occurrence of Name within a Week #. If you then wanted to show a 1 one the first occurrence of Name/Person/Week #, you could just modify the [FirstOne] variable accordingly:
=Min([Sale ID]) In ([Name];[Person];[Week #])
I think you want logic around row_number():
select t.*,
(case when 1 = row_number() over (partition by name, person, week, identifier
order by ??
)
then 1 else 0
end) as new_indicator
from t;
Note the ??. SQL tables represent unordered sets. There is no "first" row in a table or group of rows, unless a column specifies that ordering. The ?? is for such a column (perhaps a date/time column, perhaps an id).
If you only want one row to be marked, you can put anything there, such as order by (select null) or order by week.

SQL in Access, subquery pairing issue

I wrote an SQL statement in Access that looks for rows of data with the same value in their 'Code' column and then looks at those rows with the same 'Code' value and finds rows with opposite 'Money Amt' column values (for example one row would have a value of 200 and another would have -200) a column labeled line is then populated with the number '999' when pairs of these opposite values with the same code are found.
The problem is that some of my rows are pairing in odd numbered groups instead of by pairs of 2. I want there to be a 1:1 relationship for the opposing values so that they essentially negate each other.
Here is the code I used to get the result so far.
UPDATE [Actual Debt]
SET LineItem = 999
WHERE EXISTS
(SELECT * FROM [Actual Debt] as ad2
WHERE ad2.Code = [Actual Debt].Code
AND ad2.[Money Amt] = - [Actual Debt].[Money Amt]);
In the picture you can see that in the first 4 rows the code populated 2 pairs of opposing 'Money Amt' values as intended. But, in the bottom 3 rows there should have only been 1 pair of '999', but instead it has populated an odd number of rows.
How do I get the subquery to only populate the Line field for opposing pairs.
Image from before I put in the current code
Thank you in advance.
Now Gordon I do believe this can be done in MS Access. You can do just about everything in Access that you can do in other database its just a matter of figuring out the how. However in this particular case there seems to be a problem with the underlying data that is causing the current issue and without seeing the entire source table it is very hard to determine what that error is. Still I would venture to guess that if you ran your sub-Query by itself (as I show below) that you would get the data as I show below. Try running just the SELECT part of your query and see what you get.
SELECT *
FROM ActualDebt AS Ad2
WHERE Ad2.Code = ActualDebt.Code
AND Ad2.MoneyAmt = ((-1) * ActualDebt.MoneyAmt);
Most likely the Query Results are as follows based on what I see in your table
Code | MoneyAmt
MHT .3
MHT .3
MHT -.3
MHT -.3
RLO .4
RLO .6
MQR .9
MQR -.9
MQR .9
So Gordon if what I have outlined above, is the issue, then yes you will need to provide more information in order for a solution to be determine because programmatically right now there would be no way to differentiate between the first MQR .9 and the other MQR .9 -- which seems to be the source of the issue
I will keep an eye on this post and if you edit your question then I will edit this answer to help.

Record count when a certain value is present in one row and a different value is not present in another row

I have been tasked with a query that would tell me how many of a certain value are present when another value is not present in a separate row. The 2 rows do have a common field that will be the same when both are present. I have got to the following.
SELECT inci_no, count(inci_no)
FROM inc_unit
WHERE unit IN ('E08','ms08') and alm_date>='01/01/2013'
GROUP BY inci_no
So this gives me the number row for inci_no. I only need rows that have a 1 and the only unit is E08. The inci_no does not matter I have simply been using it to group by.
Thanks for your help.
As Robert said above you could write a self join. If I understand correctly, you want rows where unit is E08 and the second row is not ms08? If so, something like this might work:
Select t1.inci_no, count(t1.inci_no)
From inc_unit as t1 Inner Join inc_unit as t2 On t1.inci_no = t2.inci_no
Where t1.unit = 'E08' and t2.unit <> 'ms08' and t1.alm_date>='01/01/2013'
Group by t1.inci_no
You might have to add something to exclude joining on itself, but this should get you started.

SQL : how to Case depending of the result of the 2 latest values of one column

I am discovering SQL as I have to build queries in my new company.I have understood the basic but here is where I am stuck, maybe you could help me figure this out :
I would like to mention a product as unprocurable if sellers rejected my orders twice. Tricky part I aggregate the furniture orders for all our local offices, therefore even though I sent my purchase order(s) to one unique seller (the one with the best offer at the moment) I might have multiple lines for each item (one per office)
See below table for purchase orders, see REF1 item should be set as unprocurable as both on 21 and 31 december my orders have been rejected (no matter the seller)
http://i.stack.imgur.com/r3W3E.jpg
So to put it in logic I would like to have something like this:
For each items with 2 latest purchase orders that were both made at different dates and rejected(0 value in the table) THEN attach a note to it saying "unprocurable" else put as procurable.
IF it was only 1 value I think I could go with
Select
item
, MAX(date)
, case
when confirmed_units = 0
then 'Unprocurable'
else 'procurable'
end
From
purchase_table
Where
date between TO_DATE('01/01/2013', 'MM/DD/YYYY') AND TO_DATE('{RUN_DATE_YYYY/MM/DD}', 'YYYY/MM/DD')
But now I need to check the two latest purchase orders and that are not from the same day.
I am a bit lost, could you give a hand please?
Thanks !
Your question is a little unclear... have you tried using something along the lines of:
SELECT TOP 2 etc, etc... order by [column]

SQL Output Question

Edited
I am running into an error and I know what is happening but I can't see what is causing it. Below is the sql code I am using. Basically I am getting the general results I want, however I am not accurately giving the query the correct 'where' clause.
If this is of any assistance. The count is coming out as this:
Total Tier
1 High
2 Low
There are 4 records in the Enrollment table. 3 are active, and 1 is not. Only 2 of the records should be displayed. 1 for High, and 1 for low. The second Low record that is in the total was flagged as 'inactive' on 12/30/2010 and reflagged again on 1/12/2011 so it should not be in the results. I changed the initial '<=' to '=' and the results stayed the same.
I need to exclude any record from Enrollments_Status_Change that where the "active_status" was changed to 0 before the date.
SELECT COUNT(dbo.Enrollments.Customer_ID) AS Total,
dbo.Phone_Tier.Tier
FROM dbo.Phone_Tier as p
JOIN dbo.Enrollments as eON p.Phone_Model = e.Phone_Model
WHERE (e.Customer_ID NOT IN
(Select Customer_ID
From dbo.Enrollment_Status_Change as Status
Where (Change_Date >'12/31/2010')))
GROUP BY dbo.Phone_Tier.Tier
Thanks for any assistance and I apologize for any confusion. This is my first time here and i'm trying to correct my etiquette on the fly.
If you don't want any of the fields from that table dbo.Enrollment_Status_Change, and you don't seem to use it in any way — why even include it in the JOINs? Just leave it out.
Plus: start using table aliases. This is very hard to read if you use the full table name in each JOIN condition and WHERE clause.
Your code should be:
SELECT
COUNT(e.Customer_ID) AS Total, p.Tier
FROM
dbo.Phone_Tier p
INNER JOIN
dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE
e.Active_Status = 1
AND EXISTS (SELECT DISTINCT Customer_ID
FROM dbo.Enrollment_Status_Change AS Status
WHERE (Change_Date <= '12/31/2010'))
GROUP BY
p.Tier
Also: most likely, your EXISTS check is wrong — since you didn't post your table structures, I can only guess — but my guess would be:
AND EXISTS (SELECT * FROM dbo.Enrollment_Status_Change
WHERE Change_Date <= '12/31/2010' AND CustomerID = e.CustomerID)
Check for existence of any entries in dbo.Enrollment_Status_Change for the customer defined by e.CustomerID, with a Change_Date before that cut-off date. Right?
Assuming you want to:
exclude all customers whose latest enrollment_status_change record was since the start of 2011
but
include all customers whose latest enrollment_status_change record was earlier than the end of 2010 (why else would you have put that EXISTS clause in?)
Then this should do it:
SELECT COUNT(e.Customer_ID) AS Total,
p.Tier
FROM dbo.Phone_Tier p
JOIN dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE dbo.Enrollments.Active_Status = 1
AND e.Customer_ID NOT IN (
SELECT Customer_ID
FROM dbo.Enrollment_Status_Change status
WHERE (Change_Date >= '2011-01-01')
)
GROUP BY p.Tier
Basically, the problem with your code is that joining a one-to-many table will always increase the row count. If you wanted to exclude all the records that had a matching row in the other table this would be fine -- you could just use a LEFT JOIN and then set a WHERE clause like Customer_ID IS NULL.
But because you want to exclude a subset of the enrollment_status_change table, you must use a subquery.
Your intention is not clear from the example given, but if you wanted to exclude anyone who's enrollment_status_change as before 2011, but include those who's status change was since 2011, you'd just swap the date comparator for <.
Is this any help?