SQL Query用于选择具有包空间的储物柜

Ron*_*nze 5 sql postgresql associations

我正在使用以下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
);
Run Code Online (Sandbox Code Playgroud)

可以通过设置locker_id包的列来将包保留到储物柜.这些包最终会door_id在送到储物柜时获得,但这超出了这个问题的范围.现在,我只对预订感兴趣,这个设置给了我很大的灵活性(例如,如果在预订时有一个大门的储物柜保留一个小包装,但是储物柜有较小的门可用在交货时,我不需要重写a 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);
};
Run Code Online (Sandbox Code Playgroud)

我花了几天时间试图弄清楚如何在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)
Run Code Online (Sandbox Code Playgroud)

Pel*_*lin 0

您可以使用计算列对doors记录的剩余空间进行排序并获取最小的记录。

http://sqlfiddle.com/#!17/a8840/2

 WITH newPackage (packsize) as (
   values (1)--I used with clause to declare the new package. You can change the size of the new package from here to test different cases
)
select  d.*, 
(d.size - coalesce((select p.size from packages p where  p.locker_id = d.locker_id), 0)) remaining_size 
from 
doors d, 
newPackage
where 
d.size - coalesce((select p.size from packages p where  p.locker_id = d.locker_id), 0) >= newPackage.packsize
order by 
(d.size - coalesce((select p.size from packages p where  p.locker_id = d.locker_id), 0)) 
limit 1
Run Code Online (Sandbox Code Playgroud)