Select Exchange Rate based on Currency and Date [closed] - mysql

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I've looked around for a solution to this, but at least I was unable to find anything which would at least be similar to my case.
I need to select the exchange rate, based on the date a product was purchased.
Let me try and explain.
I have a table with Currencies:
CREATE TABLE `tblCurrencies` (
`CurrID` int(11) NOT NULL AUTO_INCREMENT,
`CurencySymbol` varchar(1) DEFAULT NULL,
`CurrencyCode` varchar(3) DEFAULT NULL,
`CurrencyDescription` varchar(100) DEFAULT NULL,
PRIMARY KEY (`CurrID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
A table with Exchange Rates:
CREATE TABLE `tblExchRates` (
`ExcID` int(11) NOT NULL AUTO_INCREMENT,
`CurrKey` int(11) DEFAULT NULL,
`Date` date DEFAULT NULL,
`Exchange` decimal(11,3) DEFAULT NULL,
PRIMARY KEY (`ExcID`),
KEY `CurrKey` (`CurrKey`),
CONSTRAINT `tblExchRates_ibfk_1` FOREIGN KEY (`CurrKey`) REFERENCES `tblCurrencies` (`CurrID`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8;
And a table with Products (note my products are listed in numbers in the table, which is OK in my case):
CREATE TABLE `tblProducts` (
`ProductID` int(11) NOT NULL AUTO_INCREMENT,
`Contract` int(11) DEFAULT NULL,
`Product` int(11) DEFAULT NULL,
`Type` varchar(100) DEFAULT NULL,
`Currency` int(11) DEFAULT NULL,
`Amount` decimal(10,0) DEFAULT NULL,
`PurchaseDate` datetime DEFAULT NULL,
PRIMARY KEY (`ProductID`),
KEY `Contract` (`Contract`),
KEY `Currency` (`Currency`),
CONSTRAINT `tblShopCart_ibfk_2` FOREIGN KEY (`Currency`) REFERENCES `tblCurrencies` (`CurrID`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `tblShopCart_ibfk_1` FOREIGN KEY (`Contract`) REFERENCES `tblContracts` (`ContractID`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3155 DEFAULT CHARSET=utf8;
In the Exchange Rates table, as an example, values are set like this:
CurrKey Date Exchange
1 15-01-2017 0.850
1 31-01-2017 0.856
1 02-02-2018 0.918
1 18-02-2018 0.905
2 04-02-2018 1.765
2 14-02-2018 1.755
And so on...
I want to have a query that select a unique exchange rate based on the date a product was purchased and the currency it was purchased.
In other words, as an example, if I have a product that was purchased on 07-02-2018, the query has to select the exchange rate which is valid in the relevant date rage that matches the purchase date and its currency. In this example, the correct exchange rage for a product purchased on 07-02-2018 which has a currkey of 1 would be 0.918
Please note that exchange rates are set on random dates (as per example above).
I managed to make this query, but it is not precise, as it sometimes returns two or more results (due to the 10 days range I set), whereas I only need 1 result:
SELECT
tblExchRates.Exchange
FROM
tblCurrencies
INNER JOIN tblExchRates ON tblExchRates.CurrKey = tblCurrencies.CurrID
WHERE
tblCurrencies.CurrencyCode = "EUR" AND
tblExchRates.Date BETWEEN (tblProducts.PurchaseDate - INTERVAL 10 DAY) AND (tblProducts.PurchaseDate + INTERVAL 10 DAY)

For a fairly simple solution you can do
SELECT
p.*
,(SELECT TOP 1 er.Exchange
FROM tblExchRates AS er
INNER JOIN tblCurrencies AS c ON er.CurrKey = c.CurrID AND c.CurrencyCode = 'EUR'
WHERE er.Date <= p.PurchaseDate
ORDER BY er.Date DESC) AS ExchangeRate
FROM
tblProducts AS p
Another option, if you have control over the schema then changing your exchange rates table to have a DateFrom and DateTo rather than just a date would then mean you can simply find the correct exchange rate using the BETWEEN keyword.

I am a beginner myself so no guarantees on correctness. I believe you have to use a certain application programming language along with SQL, for example PHP. Still, I will outline the basic steps I would take.
1. Assign the purchase currency ID and purchase date to variables using a simple SELECT statement. Assume I give the ID to targetID and date to targetDate.
2. SELECT MIN(Date) FROM tblExchRates WHERE Date <= targetDate AND CurrKey =targetID; //Select most recent date whose range includes the date of purchase among the matching currency IDs. Assign the result of this statement to another variable. Assume I used the variable dateRange.
3. SELECT Exchange FROM tblExchRates WHERE Date = targetDate; //Find the exchange rate of the selected date.
Note that there are many ways to do this. For example, you could use table JOINS (refer to this link: https://www.w3schools.com/sql/sql_join.asp ) or select columns from different tables in just one SQL statement (refer to this Stack overflow question: MySQL Select all columns from one table and some from another table). Last, you can use SQL to create variables (refer to this question: Set the variable result, from query) and then perform operations.

Related

Does this sql rewrite preserve sort order in mysql [duplicate]

This question already has answers here:
MySQL/MariaDB - order by inside subquery
(2 answers)
Closed 10 days ago.
In the book High performance mysql 3rd edition, it says
A frequent problem is having a high value for the offset. If your query looks like LIMIT
10000, 20, it is generating 10,020 rows and throwing away the first 10,000 of them,
which is very expensive.
One simple technique to improve efficiency is to do the offset on a covering index,
rather than the full rows.
Consider the following
query:
SELECT film_id, description FROM sakila.film ORDER BY title LIMIT 50, 5;
If the table is very large, this query is better written as follows:
mysql> SELECT film.film_id, film.description
-> FROM sakila.film
-> INNER JOIN (
-> SELECT film_id FROM sakila.film
-> ORDER BY title LIMIT 50, 5
-> ) AS lim USING(film_id);
This “deferred join” works because it lets the server examine as little data as possible
in an index without accessing rows, and then, once the desired rows are found, join
them against the full table to retrieve the other columns from the row.
My question is, does the second SQL preserve the same result set order as the first SQL, since it has no order by clause outside?
Here is the table DDL for quick reference:
CREATE TABLE film (
film_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(128) NOT NULL,
description TEXT DEFAULT NULL,
release_year YEAR DEFAULT NULL,
language_id TINYINT UNSIGNED NOT NULL,
original_language_id TINYINT UNSIGNED DEFAULT NULL,
rental_duration TINYINT UNSIGNED NOT NULL DEFAULT 3,
rental_rate DECIMAL(4,2) NOT NULL DEFAULT 4.99,
length SMALLINT UNSIGNED DEFAULT NULL,
replacement_cost DECIMAL(5,2) NOT NULL DEFAULT 19.99,
rating ENUM('G','PG','PG-13','R','NC-17') DEFAULT 'G',
special_features SET('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (film_id),
KEY idx_title (title),
KEY idx_fk_language_id (language_id),
KEY idx_fk_original_language_id (original_language_id),
CONSTRAINT fk_film_language FOREIGN KEY (language_id) REFERENCES language (language_id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_film_language_original FOREIGN KEY (original_language_id) REFERENCES language (language_id) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
In my experience the result will preserve the ordering of the subquery, but I'm not sure it's guaranteed. So you should repeat the ORDER BY clause.
SELECT film.film_id, film.description
FROM sakila.film
INNER JOIN (
SELECT film_id
FROM sakila.film
ORDER BY title
LIMIT 50, 5
) AS lim USING(film_id)
ORDER BY title

Querying of off a query MYSQL

I'be been googling around about nested queries but can't find anything that I can grasp about how to go about this particular operation.
First, I'll show you my DB schema
CREATE TABLE slsemp
( empID char(4) NOT NULL,
empname varchar(50) NOT NULL,
prtime enum('yes','no') NOT NULL, # we can only accept yes or no values to the part-time employee indicator
RegionID char(2) NOT NULL, # enums are often used for boolean values in a BD
PosID char(4) NOT NULL,
PRIMARY KEY (empID),
FOREIGN KEY (regionID) REFERENCES region (RegionID),
FOREIGN KEY (PosID) REFERENCES slspos(PosID));
# create the sales transactions table
CREATE TABLE slstranx
( tranxID int(10) NOT NULL AUTO_INCREMENT, #starts at a certain number, then increments accordingly
empID char(4) NOT NULL,
ProdID char(3) NOT NULL,
Qty int(5) NOT NULL,
Unitprice Decimal(5,2) NOT NULL, # please note we are capturing the unit price at the transactional level in this case
SAmt Float(10,2), #store up to 10 (TOTAL?) with 2 digits past decimal point
SalesDate date, # 'date' data type is organized as follows YYYYMMDD. You need to make sure that raw data contains the DATE in the YYYYMMDD format
# For example 20150915
PRIMARY KEY (tranxID),
FOREIGN KEY (ProdID) REFERENCES product (ProdID),
FOREIGN KEY (empID) REFERENCES slsemp (empID));
Now, I want to find employees that are in the west region that haven't made any sales. I figured I'd do this via a left outer join between the two tables then query the resulting table based off of a null tranx ID. I've got it most of the way there, here's my query:
SELECT e.empID, t.tranxID, e.RegionID
FROM slsemp e LEFT OUTER JOIN slstranx t ON e.empID=t.empID
WHERE e.RegionID='WS'
My question is, how do I query based of the criteria of this resultant table. If I could do that, I simply would need a selection with criteria of slstranxID=null.
You can use left join adding where slstranx.empID is null
select distinct empID, empName
from slsemp
left join slstranx on slsemp.empID = slstranx.empID
where slsemp.RegionID = 'WS'
and slstranx.empID is null
if the column from the table in left join is null mean that don't match .. so don't have sales

Mysql stored functions and groupwise min [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Schema
Database schema is simplified
Events table
This table stores events.
CREATE TABLE `Events` (
`event_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`isPublic` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Places table
Simple table that stores places. One event can be in more than one place.
CREATE TABLE `Places` (
`place_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
PRIMARY KEY (`place_id`),
KEY `latind` (`latitude`,`longitude`)
) ENGINE=InnoDB CHARSET=latin1;
Rules table
Table that stores schedules of events. One event can have more that one schedule. All dates are in unixtimestamp format. Regular means that this rule has some repeating schedule that is stored in RegularRules table.
CREATE TABLE `Rules` (
`rule_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`start_date` int(11) NOT NULL,
`end_date` int(11) NOT NULL,
`regular` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`rule_id`),
KEY `endindx` (`end_date`)
) ENGINE=InnoDB CHARSET=latin1;
RegularRules
Table that stores repeatable schedules in the following format. day_start/end means number of seconds from the beggining of the day (00:00) to the starting of the event. For example, event takes place every monday from 10:00 to 18:00. We will store start_date and end_date in Rules table, these values represent time limits of the event. In the RegularRules table we will have 36000 in mon_start and 64800 in mon_end.
CREATE TABLE `RegularRules` (
`repetition_id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) unsigned NOT NULL,
`mon_start` int(11) DEFAULT NULL,
`tue_start` int(11) DEFAULT NULL,
`wed_start` int(11) DEFAULT NULL,
`th_start` int(11) DEFAULT NULL,
`fr_start` int(11) DEFAULT NULL,
`sat_start` int(11) DEFAULT NULL,
`sun_start` int(11) DEFAULT NULL,
`mon_end` int(11) DEFAULT NULL,
`tue_end` int(11) DEFAULT NULL,
`wed_end` int(11) DEFAULT NULL,
`th_end` int(11) DEFAULT NULL,
`fr_end` int(11) DEFAULT NULL,
`sat_end` int(11) DEFAULT NULL,
`sun_end` int(11) DEFAULT NULL,
PRIMARY KEY (`repetition_id`),
KEY `fk_rule_id_regularrules_idx` (`rule_id`),
CONSTRAINT `fk_rule_id_regularrules` FOREIGN KEY (`rule_id`)
REFERENCES `Rules` (`rule_id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB CHARSET=latin1;
Events-Places-Rules
Table that connects all of the above tables.
CREATE TABLE EPR (
`holding_id` bigint(30) NOT NULL AUTO_INCREMENT,
`event_id` bigint(20) unsigned NOT NULL,
`place_id` bigint(20) unsigned NOT NULL,
`rule_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`holding_id`),
UNIQUE KEY `compound` (`place_id`,`event_id`,`rule_id`),
KEY `FK_Places-Company Events-Rules_Events_event_id` (`event_id`),
KEY `FK_Places-Company Events-Rules_Places_place_id` (`place_id`),
KEY `FK_Places-Company Events-Rules_Rules_rule_id` (`rule_id`),
CONSTRAINT `FK_Places-Company Events-Rules_Events_event_id`
FOREIGN KEY (`event_id`) REFERENCES `Events` (`event_id`) ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `FK_Places-Company Events-Rules_Rules_rule_id`
FOREIGN KEY (`rule_id`) REFERENCES `Rules` (`rule_id`) ON DELETE CASCADE ON
UPDATE CASCADE,
CONSTRAINT `fk_place_id_pcerc` FOREIGN KEY (`place_id`)
REFERENCES `Places` (`place_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB CHARSET=latin1;
Stored functions
There are two stored functions. GETBEGINS and GETENDS. Parameters: rule_id, timestamp,curtimestamp.Timestamp is unixtimestamp of the day, curtimestamp is the unixtimestamp of the beggining of the current day.
These functions work as follows. For each rule they are returning the beggining of the rule(begins) and the ending(ends). If the rule is not repeatable, they return start_date and end_date that are stored in the Rules table. If the rule is repeatable, they construct begins and ends of the closest non-null day_start/day_end of the RegularRules table. For instance, there is an event that has 2 rules. The first one is not repeatable with begins start_timestamp and ends end_timestamp. The second one is repeatable and has just two non-null fields: mon_start = 36000 and mon_end = 64800. GETBEGINS will turn mon_start in unixtimestamp based on current unixtimetamp and current unixtimestamp of the beggining of the day. GETBEGINS works simmilarly. Code of these functions will be provided if necessary.
Problematic query
This query should return ongoing geographically- and chronologically-closest events. Places should be distinct. So query should for each place return chronologically closest event and at the end sort resulting values depending on time and distance with some coefficients (I think sorting part will be moved to the server-side language like PHP. If you have suggestions about this sorting I am open to any solution). For example, there are 5 movies in 10 cinemas near by. Each cinema has 100 schedules. Query should return for each cinema the chronologically closest movie and then sort movies and cinemas depending on two values time and distance.
Intended query
latpoin,longpoint,r - are coordinates and radius that are passed to the script,
curstamp - unixtimestamp of the beggining of the day,
timestamp - current unixtimestamp
SELECT
epr.event_id,
epr.place_id,
epr.rule_id,
(6371 * ACOS(COS(RADIANS(latpoint)) * COS(RADIANS(latitude)) *
COS(RADIANS(longitude) - RADIANS(longpoint)) + SIN(RADIANS(latpoint)) *
SIN(RADIANS(latitude)))) AS distance,
p.latitude,
p.longitude,
GETBEGINS(r.rule_id, curstamp, timestamp) AS begins,
GETENDS(r.rule_id, curstamp, timestamp) AS ends,
MIN(ABS(GETBEGINS(r.rule_id, curstamp, timestamp) - timestamp)) AS
time_min
FROM
Events e
INNER JOIN
EPR epr ON e.event_id = epr.event_id
INNER JOIN
Places p ON epr.place_id = p.place_id
INNER JOIN
Rules r ON epr.rule_id = r.rule_id
WHERE
r.end_date >= timestamp
AND latitude BETWEEN latpoint - (r / 111.045) AND latpoint + (r /
111.045)
AND longitude BETWEEN longpoint - (r / (111.045 *
COS(RADIANS(latpoint)))) AND longpoint + (r / (111.045 *
COS(RADIANS(latpoint))))
AND e.isPublic = 1
GROUP BY epr.place_id
As stated in the topic this query mixes returning values. To be more specific it matches wrong rule_id,begins,ends to the place_id group.
Moreover this query performs quite poorly. Table's size: Events - 3000rows, Places- 8000rows, Rules 18000rows, EPR-15000rows. These query works approximately 1.8 second when using index hint (use index compound) and 1.2 without one. Without using index hint query makes full table scan.
I have read official mysql docs regarding this subject. However their solution is not sutable because of user-calculated values (GETBEGINS and GETENDS).
Question
Query provided in the Intended query section has groupwise min problem because of the way mysql handles group by. So possible solution is to make functions GETBEGINS and GETENDS user-defined aggregated functions in this way mysql possibly will return appropiate result? Is this solution logical? Will making functions GETBEGINS and GETENDS aggregated help? Will mysql return appropiate data in that case?
Conclusion
Comments about provided solutions, new solutions, comments about indexing and about database architecture are appreciated and welcomed.
The groupwise max is not guaranteed to work. In fact, MariaDB broke it, but provided a setting to get it back. This is what I am referring to:
SELECT *
FROM
( SELECT ... ORDER BY ... )
GROUP BY ...
where you want the first (or last) in each group from the inner query. The problem is that SQL is free to optimize away that intent.
The groupwise max code in the docs is terribly inefficient.
To speed up the query, a likely bit of help is to isolate the Rules or Places part of the WHERE clause and make that into a subquery which returns just the PRIMARY KEY of the corresponding table. Then put that into a JOIN with all the tables (including a JOIN back to the same table). You already have a "covering index" for that subquery so that it can be "Using index" (in the jargon used by EXPLAIN).
Is innodb_buffer_pool_size set to about 70% of available RAM?
BIGINT takes 8 bytes; you could probably live with MEDIUMINT UNSIGNED (0..16M). Smaller --> more cacheable --> less I/O --> faster.
The pair of DOUBLEs for lat/lng take 16 bytes. A FLOAT pair would take 8 bytes and have 6-foot / 2m resolution. Or DECIMAL(6,4) for latitude and (7,4) for longitude for 7 bytes and a 52 foot / 16m resolution. Good enough for "stores", especially since you are using a 'square' instead of a 'circle' for distance.
Code for "find the nearest ..." is hard to optimize. Here is the best I have come up with: http://mysql.rjweb.org/doc.php/latlng

MySQL Stored Procedure Getting distinct count, displaying latest records only

I have the following inside my stored procedure that retrieves unique records from player names that have a faction of Neutral:
SELECT
COUNT(DISTINCT Name) into #neutcount
FROM
dim5players
WHERE
Faction ='Neutral';
UPDATE dim5stats
SET Value = #neutcount
WHERE
Function = 'Neutral';
This works find and dandy. The problem is that I have a field called Date as well.
I want to select the lastest date of the records to be listed in the count instead of a random record from the unique "Name" record.
This is a history table, and it records daily changes of the records, where Name can appear several times. I need to count only the latest records that have a faction of neutral with their latest records only. Some people change factions from time to time. I only care about their latest faction.
This is the structure:
CREATE TABLE `dim5players` (
`id` CHAR(64) NOT NULL,
`name` VARCHAR(45) NOT NULL,
`rank_name` VARCHAR(20) NULL DEFAULT NULL,
`level` INT(11) NOT NULL,
`defender_rank_id` INT(11) NULL DEFAULT NULL,
`Faction` VARCHAR(15) NOT NULL,
`Organization` VARCHAR(100) NULL DEFAULT NULL,
`Date` DATE NOT NULL,
`Updated` BIT(1) NOT NULL,
UNIQUE INDEX `id_UNIQUE` (`id`) USING HASH,
INDEX `name_index` (`name`) USING HASH,
INDEX `date_index` (`Date`) USING HASH,
INDEX `updated_index` (`Updated`) USING HASH,
INDEX `faction_index` (`Faction`) USING HASH
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
After a discussion with Michael i think i figured out what he needs:
"I want the Last Updated record of each name"
SELECT
name ,
MAX(Date) as last_date
FROM
dim5players
WHERE
Faction ='Neutral'
GROUP BY
name
"I just want to count the latest date on each NAME that still holds the faction of Neutral"
SELECT
COUNT(last_date)
FROM (
SELECT
name ,
MAX(Date) as last_date
FROM
dim5players
WHERE
Faction ='Neutral'
GROUP BY
name
) as tmp
#Michael : Let me know if i understood you requirements correctly

Mysql select max with threshold

I have the following 3 tables as part of a car booking system:
CREATE TABLE `b_booking` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`b_car_id` VARCHAR(15) NOT NULL,
`uc_user_id` INT(11) NOT NULL,
`booking_date` DATE NOT NULL,
`delivery_date` DATE NOT NULL,
`delivery_location` INT(10) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `FK_b_booking_b_car` (`b_car_id`),
INDEX `FK_b_booking_uc_users` (`uc_user_id`),
INDEX `FK_b_booking_b_location` (`delivery_location`),
CONSTRAINT `FK_b_booking_b_location` FOREIGN KEY (`delivery_location`) REFERENCES `b_location` (`id`),
CONSTRAINT `FK_b_booking_b_car` FOREIGN KEY (`b_car_id`) REFERENCES `b_car` (`id`),
CONSTRAINT `FK_b_booking_uc_users` FOREIGN KEY (`uc_user_id`) REFERENCES `uc_users` (`id`)
CREATE TABLE `b_car` (
`id` VARCHAR(15) NOT NULL,
`b_carmodel_id` INT(10) NOT NULL,
`day_cost` INT(10) NOT NULL,
`location` INT(10) NOT NULL,
`model_year` SMALLINT(4) NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_b_car_b_carmodel` (`b_carmodel_id`),
INDEX `FK_b_car_b_location` (`location`),
CONSTRAINT `FK_b_car_b_location` FOREIGN KEY (`location`) REFERENCES `b_location` (`id`),
CONSTRAINT `FK_b_car_b_carmodel` FOREIGN KEY (`b_carmodel_id`) REFERENCES `b_carmodel` (`id`)
CREATE TABLE `b_location` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`adress` VARCHAR(100) NOT NULL,
`b_postal_zip` SMALLINT(4) UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_b_location_b_postal` (`b_postal_zip`),
CONSTRAINT `FK_b_location_b_postal` FOREIGN KEY (`b_postal_zip`) REFERENCES `b_postal` (`zip`)
A given car (b_car) will have an int representing av location where a car can be picked up or delivered. However, this location will change, due to the fact that a customer can pick up the car on one location, and deliver at another. When a customer registers a booking (b_booking), he/she also register at what location the car will be delivered (delivery_location).
I'm however having a lot of problems with what seems to me shouldn't be that hard to do: Lets say a car is at location 1 at the beginning of the month. Then, customer X register a booking for 15-20. and registers a delivery at location 2. Then customer Y wishes to book the same car. So I need a query which takes into account the date and location.
SELECT c.id, c.location, b.delivery_location, MAX(b.delivery_date) FROM b_car c
LEFT JOIN b_booking b ON b.b_car_id = c.id
WHERE b.delivery_date < '2012-11-28' OR b.delivery_date IS NULL
GROUP BY c.id;
I have tried something similar to this. I will pick all cars which has no bookings with the left join, and it will also pick the last booking (the last booking related to given date). The problem is, of course, that the where condition also excludes any booking with a date higher than the provided date. Also, with this solution I'm forced to get both the location (from b_car) and the delivery location (from b_booking), and perhaps evaluate null on the delivery_location with php or something.. which really doesnt seem optimal.
Any good solutions?
Thanks
I am not sure what your question is. I think your question is to find out which cars are available based on the planning in the booking system on a given day. In that case the only info you need is the ids from the cars and the location and according to the booking system.
BTW I would suggest to add time to your table, because you may want to rent out a car the same day. If customer A returns the car before 12:00 you can easily rent out the same car at 13:00 to customer B.
SELECT c.id, b.delivery_location, b.delivery_date FROM b_car AS c
LEFT JOIN b_booking AS b ON b.id = c.id
WHERE b.delivery_date = '2012-11-28' and b.delivery_location = 1;
I simplified you query, because I think this will give you the information you need. If a customer wants to rent a car you need to know if the car is available in the planning at the specified location.
If you want to know the availability between to dates use WHERE b.delivery_date between [start date] AND [end date].
I suspect that the type of car is important for the customer, so perhaps it is better to look for a specific car type available at the location of choice.
Furthermore, I would suggest checking if the car is actual at the desired location at the delivery time.