【问题标题】:SQL Query to select lockers with room for packageSQL 查询以选择有空间的储物柜用于包裹
【发布时间】:2019-03-21 16:53:59
【问题描述】:

我正在使用以下 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)

【问题讨论】:

  • 你将如何用javascript编写它?这会让你很清楚你到底想做什么......我对第 2 步有点含糊。
  • 另外 - 您可以调查 PL/pgSQL 以完成更复杂的任务。
  • @Dave 这个要求我也不清楚,但最好的解决方案可能是 SQL 查询。
  • @Dave 用有效的 JS 代码更新了问题。
  • 您能否添加一些示例数据和预期结果?我认为这将有助于我更好地理解问题。

标签: sql postgresql associations


【解决方案1】:
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)

【讨论】:

    【解决方案2】:

    您可以使用计算列对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
    

    【讨论】:

      猜你喜欢
      • 2022-08-23
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-21
      相关资源
      最近更新 更多