Я создаю интеллектуальную систему резервирования шкафчиков со следующими таблицами Postgres:
CREATE TABLE lockers (
id serial primary key
)
CREATE TABLE doors (
id serial primary key,
locker_id integer NOT NULL,
size integer
);
CREATE TABLE packages (
id serial primary key,
locker_id integer NOT NULL,
size integer
);
Пакет можно зарезервировать для шкафчика, установив столбец locker_id
пакета.Пакеты в конечном итоге получат door_id
, когда они будут доставлены в шкафчик, но это выходит за рамки этого вопроса.На данный момент я просто заинтересован в бронировании, и эта настройка дает мне большую гибкость (например, если небольшой пакет зарезервирован для шкафчика, который имеет одну большую дверь во время бронирования, но в шкафчике есть двери меньшего размераво время доставки мне не нужно переписывать door_id
. Я просто назначаю его наименьшей возможной двери).
Все работает отлично, но теперь я хочу написать запрос, который может выбрать все шкафчики, в которых есть место для нового пакета с заданным размером.Моя проблема в том, что я не могу просто сделать JOIN
, чтобы выбрать пустые двери, потому что пакеты знают только о шкафчике.Для каждого шкафчика мне нужно сделать что-то вроде Find the smallest possible door for each package, and see if the new package fits in any of the remaining doors
.Я легко могу написать это на JavaScript так:
const canFitPackage = (reservations, doors, newPackage) => {
const sortedReservations = reservations
.slice()
.sort((a, b) => a.size - b.size)
.reverse();
const sortedDoors = doors.slice().sort((a, b) => a.size - b.size);
for (let i = 0; i < sortedReservations.length; i++) {
const res = sortedReservations[i];
for (let j = 0; j < sortedDoors.length; j++) {
const door = sortedDoors[j];
if (door.size >= res.size) {
sortedDoors.splice(j, 1);
break;
}
}
}
return sortedDoors.some(door => door.size >= newPackage.size);
};
Я потратил несколько дней, пытаясь понять, как это сделать в SQL, но пока мне не повезло.Мне интересно, действительно ли это можно сделать в вызове SQL или мне нужно написать функцию Postgres.Любая помощь приветствуется.
Обновление
После долгих попыток попробовать разные вещи, я пришел к этому SQL-запросу, который делает это для меня.Я уверен, что это медленно и неэффективно, поэтому любые отзывы и советы приветствуются.
WITH
locker_doors AS (
SELECT * FROM doors
--ADD INNER JOIN ON LOCKER
--ADD WHERE CLAUSE ON LOCKERS
),
all_combinations AS (
SELECT locker_doors.id AS door_id, locker_doors.size AS door_size, locker_doors.locker_id, packages.id AS package_id, packages.size AS package_size
FROM locker_doors
JOIN packages ON locker_doors.locker_id = packages.locker_id AND locker_doors.size >= packages.size
ORDER BY packages.size DESC, locker_doors.size ASC
),
distinct_doors AS (
SELECT DISTINCT ON (door_id) * FROM all_combinations
),
package_placements AS (
SELECT DISTINCT ON (package_id) * FROM distinct_doors
)
SELECT DISTINCT ON (locker_id) locker_id
FROM locker_doors
WHERE id NOT IN (SELECT door_id FROM package_placements)