Update access column from existing values - ms-access

I have a MS access table with the following columns and sample records.
How do I update the adDate value with the least LastSaleDate for each ProductID.
orderID productID lastsaleDate adDate
1 1 10/20/2012
2 1 5/10/2007
3 1 4/1/2004
4 1 20/11/2011
5 2 10/10/2010
6 2 12/10/1972
For example the adDate for ProductID 1 will be 4/1/2004
and for ProductID 2 will be 12/10/1972

You can use DMin:
UPDATE sales
SET sales.adDate = DMin("lastsaleDate","sales","productID=" & productid)

Unless you have a compelling reason to actually store adDate values in your table, consider simply computing adDate with a query any time you need it. That way you don't risk ever displaying adDate values which have not been updated to reflect the latest changes to the underlying data.
SELECT
y.orderID,
y.productID,
y.lastsaleDate,
sub.adDate
FROM
YourTable AS y
INNER JOIN
(
SELECT productID, Min(lastsaleDate) AS adDate
FROM YourTable
GROUP BY productID
) AS sub
ON y.productID = sub.productID;

Related

MySQL update with conditions based on another tables value

I have two tables in MySQL. I would like to set the value of the 'Total' column to be equal to the Ratio x (Table A column if the item begins with A) or Ratio x (Table B column if the item begins with B) and the Month column in both tables match.
create table zeus(id int primary key,
Month varchar(10),
Items varchar(20),
Ratio decimal(3,2),
Total decimal(10,2));
create table ares(id int primary key,
Month varchar(10),
`Value A` decimal(10,2),
`Value B` decimal(10,2));
id
Month
Items
Ratio
Total
1
May
Bag
0.50
2
May
Apple
0.3
3
May
Bottle
0.25
4
May
Acorn
0.1
5
May
Alarm Clock
0.6
6
May
Bottle
0.25
id
Month
Total A
Total B
1
May
600
800
2
June
780
400
I have tried this
update zeus
set Total = (CASE
WHEN Items like ('A%') and Month = 'May'
THEN Ratio * (select(ares.`Value A`)
WHERE Month = 'May')
WHEN Items like ('B%') and Month = 'May'
THEN Ratio * (select(ares.`Value B`)
WHERE Month = 'May')
END);
But I can't seem to figure it out.
It looks like you just want:
update zeus
inner join ares using (Year,Month)
set zeus.Total = case
when zeus.Items like 'A%' then ares.`Value A` * zeus.Ratio
when zeus.Items like 'B%' then ares.`Value B` * zeus.Ratio
end
That will set the Total to null if Items starts with neither A nor B; add an else clause if you want it set to blank or left as the existing zeus.Total value.
Note that having arrays of column names for related values rather than a separate table with one value per row is usually considered bad database design.

Conditional counting of consecutive rows

For a given current client i am trying to find how many consecutive years they have renewed a policy with us. My thinking on how to do this is to match a field in the current row with the previous row. I'm trying to write a function for this but if there is an easier way please let me know. Here is what i have for the function
Option Compare Database
'Renewal Count Returns count of consecutive renewals
Public Function RenewCount(strLocationID As Integer, _
strQuoteID As Integer, _
strOriginalQuoteID As Variant) As String
Static strLastLocationID As Integer
Static strLastQuoteID As Integer
Static strCount As Integer
If strLocationID = strLastLocationID And strOriginalQuoteID = strLastQuoteID Then
strCount = strCount + 1
Else
strLastLocationID = strLocationID
strLastQuoteID = strQuoteID
strCount = 0
End If
RenewCount = strCount
End Function
Here is a little sample of the data
LocationID QuoteID OriginalQuoteID
2 1094117
2 1125718 1094117
2 1148296 1125718
2 1176466 1148296
5 1031892
5 1044976 1031892
5 1059216 1044976
5 1077463 1059216
There are also dates for each policy that i can manipulate as well.
My idea would be to have the following and just find the max of the last column for each location.
LocationID QuoteID OriginalQuoteID Renewal_Count
2 1125718 1094117 0
2 1148296 1125718 1
2 1176466 1148296 2
5 1031892 0
5 1044976 1031892 1
5 1059216 1044976 2
5 1077463 1059216 3
5 1098124 1077463 4
5 1100215 0
5 1198714 1100215 1
5 1254125 1198714 2
Any help would be appreciated. Thanks
I forgot to mention that this has been sorted on the location ID and that OriginalQuoteID will be null for any New policy. When i try to run the function i get #num! in the column for a majority of the rows. What i want is for a given QuoteID the number of consecutive renewals there have been. So for the above for locationID 5 QuoteID 1254125 there have been 2 Renewals.
This might work (appears to be with my tests) - create a cartesian product on itself, link the QuoteID to the OriginaQuoteID and count.
SELECT T1.LocationID,
T1.QuoteID,
T1.OriginalQuoteID
FROM Table1 T1, Table1 T2
WHERE T1.QuoteID = T2.OriginalQuoteID
to get the count per LocationID (add 1 to count the Null field):
SELECT COUNT(*)+1
FROM Table1 T1, Table1 T2
WHERE T1.QuoteID = T2.OriginalQuoteID
GROUP BY T1.LocationID
or if you prefer joins:
SELECT COUNT(*)+1
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.QuoteID = T2.OriginalQuoteID
GROUP BY T1.LocationID

SQL group by, how to define which record for each group, eg. the latest, is used

I have a table that stores a reference for each product-identifier, however there are some duplicate records - ie. a product may have been submitted more than once so has more than one reference. Each record is timestamped with the updated column.
I need a query that will only give one (non-empty) reference per product-identifier but that crucially will only select the LATEST record for each product.
So if the original table is this:
id updated product-identifier reference
------------------------------------------------------------
1 2014-11-10 07:47:02 9876543210123 98043hjdww98324322
2 2014-11-10 07:53:24 9897434243242 89f7e9wew329f080re
3 2014-11-12 10:51:10 9876543210123 48308402jfjewkfwek
4 2014-11-12 12:53:24 9876543210123 89739432bkjfekwjfk
5 2014-11-12 12:55:16 9876543210321 21321hhfioefhewfoe
6 2014-11-13 01:01:10 9897434243242
7 2014-11-13 01:05:24 9897434243242 1232423jhdksffewfe
The query should return just these records:
id updated product-identifier reference
------------------------------------------------------------
4 2014-11-12 12:53:24 9876543210123 89739432bkjfekwjfk
5 2014-11-12 12:55:16 9876543210321 21321hhfioefhewfoe
7 2014-11-13 01:05:24 9897434243242 1232423jhdksffewfe
I have tried
SELECT * FROM tablename WHERE reference !='' GROUP BY product-identifier ORDER BY updated DESC
and this gives only one record for each product, but not the latest - it is grouping before sorting.
Help greatly appreciated!
I usually do this by having a subquery that selects the highest timestamp for each group (product_identfier in your case) and then use that to select the row I want. Like this
select *
from tablename a
where a.updated = (select max(updated)
from tablename b
where a.product_identifier = b.product_identifier)
There are many ways to do this. If you want the latest record, here is a method using not exists:
select t.*
from tablename t
where not exists (select 1
from tablename t2
where t2.product_identifier = t.product_identifier and
t2.updated > t.updated
);

Creating a frequency table in Access VBA

I have a table where different participants are given multiple boxes of medicines on multiple days. I am trying to create a frequency table showing how much medicines have been distributed by the number of boxes to the participants.
The result I'm looking for is -
2 boxes = 1 (since only Lynda got a total of 2 boxes), 4 boxes = 2 (since Ryan and Rinky both got a total of 4 boxes after adding up the medicine boxes)
Please let me know what approach would be the best in this case.
Thanks for your help.
-Nams
I think you want:
SELECT t.SumOf, Count(t.[PARTICIPANT ID]) AS CountOf
FROM (SELECT Table1.[PARTICIPANT ID], Sum(Table1.MEDICINE_BOX) AS SumOf
FROM Table1
GROUP BY Table1.[PARTICIPANT ID]) AS t
GROUP BY t.SumOf;
Where table1 is the name of your table.
If your table is like this:
medicine_dispense
participantID date amount_boxes
ABC 8/29/12 1
ABC 8/30/12 2
XYZ 8/29/12 1
XYZ 8/30/12 1
then a query like this:
select
amount_boxes, count(participantID)
from
medicine_dispense
should work
I'll use generic SQL. You can paste SQL into Access queries in SQL view. (You might have to delete the CHECK() constraint.)
create table participant_meds (
participant varchar(10) not null,
distribution_date date not null default current_date,
num_boxes integer not null check (num_boxes > 0),
primary key (participant, distribution_date)
);
insert into participant_meds values ('Ryan', '2012-02-03', 1);
insert into participant_meds values ('Ryan', '2012-06-07', 3);
insert into participant_meds values ('Rinky', '2012-02-28', 4);
insert into participant_meds values ('Lynda', '2012-03-04', 2);
insert into participant_meds values ('Russ', '2012-04-05', 2);
insert into participant_meds values ('Russ', '2012-05-08', 2);
insert into participant_meds values ('Russ', '2012-06-12', 2);
Resulting data, sorted, for copy/paste.
participant distribution_date num_boxes
Lynda 2012-03-04 2
Rinky 2012-02-28 4
Russ 2012-04-05 2
Russ 2012-05-08 2
Russ 2012-06-12 2
Ryan 2012-02-03 1
Ryan 2012-06-07 3
This query gives you the total boxes per participant.
select sum(num_boxes) boxes, participant
from participant_meds
group by participant;
6;"Russ"
2;"Lynda"
4;"Ryan"
4;"Rinky"
Use that query in the FROM clause as if it were a table. (I'd consider storing that query as a view, because I suspect that the total number of boxes per participant might be useful. Also, Access has historically been good at optimizing queries that use views.)
select boxes num_boxes, count(participant) num_participants
from (select sum(num_boxes) boxes, participant
from participant_meds
group by participant) total_boxes
group by num_boxes
order by num_boxes;
num_boxes num_participants
--
2 1
4 2
6 1

MySQL - What's wrong with the query?

I am trying to query a database to find the following.
If a customer searches for a hotel in a city between dates A and B, find and return the hotels in which rooms are free between the two dates.
There will be more than one room in each room type (i.e. 5 Rooms in type A, 10 rooms in Type B, etc.) and we have to query the database to find only those hotels in which there is at least one room free in at least one type.
This is my table structure:
**Structure for table 'reservations'**
reservation_id
hotel_id
room_id
customer_id
payment_id
no_of_rooms
check_in_date
check_out_date
reservation_date
**Structure for table 'hotels'**
hotel_id
hotel_name
hotel_description
hotel_address
hotel_location
hotel_country
hotel_city
hotel_type
hotel_stars
hotel_image
hotel_deleted
**Structure for table 'rooms'**
room_id
hotel_id
room_name
max_persons
total_rooms
room_price
room_image
agent_commision
room_facilities
service_tax
vat
city_tax
room_description
room_deleted
And this is my query:
$city_search = '15';
$check_in_date = '29-03-2010';
$check_out_date = '31-03-2010';
$dateFormat_check_in = "DATE_FORMAT('$reservations.check_in_date','%d-%m-%Y')";
$dateFormat_check_out = "DATE_FORMAT('$reservations.check_out_date','%d-%m-%Y')";
$dateCheck = "$dateFormat_check_in >= '$check_in_date' AND $dateFormat_check_out <= '$check_out_date'";
$query = "SELECT $rooms.room_id,
$rooms.room_name,
$rooms.max_persons,
$rooms.room_price,
$hotels.hotel_id,
$hotels.hotel_name,
$hotels.hotel_stars,
$hotels.hotel_type
FROM $hotels,$rooms,$reservations
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_id = $rooms.hotel_id
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot
FROM $reservations
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'";
The number of rooms already reserved in each room type in each hotel will be stored in the reservations table.
The thing is the query doesn't return any result at all. Even though it should if I calculate it myself manually.
I tried running the sub-query alone and I don't get any result. And I have lost quite some amount of hair trying to de-bug this query from yesterday. What's wrong with this? Or is there a better way to do what I mentioned above?
Edit: Code edited to remove a bug. Thanks to Mark Byers.
Sample Data in reservation table
1 1 1 2 1 3 2010-03-29 2010-03-31 2010-03-17
2 1 2 3 3 8 2010-03-29 2010-03-31 2010-03-18
5 1 1 5 5 4 2010-03-29 2010-03-31 2010-03-12
The sub-query should return
Room ID : 1 Rooms Booked : 7
Room ID : 2 Rooms Booked : 8
But it does not return any value at all.... If i remove the dateCheck condition it returns
Room ID : 2 Rooms Booked : 8
Your problem is here:
$rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations,$rooms
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'"
You are doing a subtraction total_rooms - (tot, id) where the first operand is a scalar value and the second is a table with two columns. Remove one of the columns in the result set and make sure you only return only one row.
You also should use the JOIN keyword to make joins instead of separating the tables with commas. That way you won't forget to add the join condition.
You probably want something along these lines:
SELECT column1, column2, etc...
FROM $hotels
JOIN $rooms
ON $hotels.hotel_id = $rooms.hotel_id
JOIN (
SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations
JOIN $rooms
ON ??? /* Aren't you missing something here? */
WHERE $dateCheck
GROUP BY $reservations.room_id
) AS T1
ON T1.id = room_id
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - T1.tot > '0'