0

好的,我试图通过抽象出细节来简化我的问题,但恐怕我不清楚并且不符合主持人的要求。因此,我将更详细地发布包含我的问题的完整查询以及我正在努力解决的实际查询。如果问题仍然不充分,请您就不清楚的地方发表评论,我会尽力澄清。

首先,这是返回每张床的所有分配行的当前查询:

SELECT 
  beds.bed_id,
  beds.bedstatus,
  beds.position as bed_position,
  rooms.room_id,
  rooms.room,
  wings.wing_id,
  wings.name as wing_name,
  buildings.building_id,
  buildings.name as building_name,
  assignments.assignment_id,
  assignments.student_id,
  assignments.assign_dt,
  assignments.assigned_by,
  assignments.assignment_status,
  assignments.expected_arrival_dt as arrival_dt,
  assignments.room_charge_type,
  students.first_name,
  students.last_name,
  meal_plans.name as meal_plan_name,
  room_rates.rate_name
FROM
  beds
LEFT JOIN 
  rooms ON (beds.room_id = rooms.room_id)
LEFT JOIN
  wings ON (rooms.wing_id = wings.wing_id)
LEFT JOIN
  buildings ON (wings.building_id = buildings.buildings_id)
LEFT JOIN assignments ON 
  ((beds.bed_id=assignments.bed_id) AND (term_id = @term_id))
LEFT JOIN
  students ON (assignments.student_id = students.student_id)
LEFT JOIN
  meal_plans ON (assignments.meal_plan_id = meal_plans.meal_plan_id)
LEFT JOIN
  room_rates ON (room_rate_id = room_rates.room_rate_id)
WHERE
  (
    (rooms.room IS NOT NULL) AND
    (rooms.assignable = 1) AND
    (buildings.active = 1) AND
    (buildings.building_id = @building_id)
  )
ORDER BY BY rooms.room;

问题是每个房间的“分配”表中可能有多行,由“assignment_status”字段区分,我希望每个分配都有一行。我想根据 assignment_status 中的值确定要选择哪个分配行。也就是说,如果分配状态为“活动”,我想要那一行,否则,如果有一行状态为“等待批准”,那么我想要那一行,等等......

Barmar 的建议如下:

LEFT JOIN (SELECT *
       FROM OtherTable
       WHERE <criteria>
       ORDER BY CASE status
                    WHEN 'Active' THEN 1
                    WHEN 'Waiting Approval' THEN 2
                    WHEN 'Canceled' THEN 3
                    ...
                END
       LIMIT 1) other

这非常有帮助,我尝试了这种方法:

SELECT 
  beds.bed_id,
  beds.bedstatus,
  beds.position as bed_position,
  rooms.room_id,
  rooms.room,
  wings.wing_id,
  wings.name as wing_name,
  buildings.building_id,
  buildings.name as building_name,
  assign.assignment_id,
  assign.student_id,
  assign.assign_dt,
  assign.assigned_by,
  assign.assignment_status,
  assign.expected_arrival_dt as arrival_dt,
  assign.room_charge_type,
  students.first_name,
  students.last_name,
  meal_plans.name as meal_plan_name,
  room_rates.rate_name
FROM
  beds
LEFT JOIN 
  rooms ON (beds.room_id = rooms.room_id)
LEFT JOIN
  wings ON (rooms.wing_id = wings.wing_id)
LEFT JOIN
  buildings ON (wings.building_id = buildings.buildings_id)

LEFT JOIN (SELECT *
           FROM assignments
           WHERE ((assignments.bed_id==beds.bed_id) AND (term_id = @term_id))
           ORDER BY CASE assignment_status
                        WHEN 'Active' THEN 1
                        WHEN 'Waiting Approval' THEN 2
                        WHEN 'Canceled' THEN 3
                    END
           LIMIT 1) assign  

LEFT JOIN
  students ON (assign.student_id = students.student_id)
LEFT JOIN
  meal_plans ON (assign.meal_plan_id = meal_plans.meal_plan_id)
LEFT JOIN
  room_rates ON (room_rate_id = room_rates.room_rate_id)
WHERE
  (
    (rooms.room IS NOT NULL) AND
    (rooms.assignable = 1) AND
    (buildings.active = 1) AND
    (buildings.building_id = @building_id)
  )
ORDER BY rooms.room;

但我意识到,这里的问题是 OtherTable (assignments) 基于 FK 加入到父查询中:

  ((beds.bed_id=assignments.bed_id) AND (term_id = @term_id))

所以我不能做子选择,因为beds.bed_id 不在子选择的范围内。因此,Barmar 的评论表明连接条件需要在子选择之外——但我无法弄清楚如何将结果限制为每个房间的一行并将连接移到子选择之外。我想知道 travelboy 使用 GROUP BY 的建议是否更有成效,但无法确定应该如何进行分组。

让我知道我是否可以提供额外的说明。

原始问题:

我需要从表 A 对另一个表中的单行进行 LEFT JOIN,表 B 满足某些条件(表 B 中可能有多个或没有满足条件的行)。如果有多行,我想根据表 B 中字段的值来选择 B 中的哪一行要加入。例如,如果 B 中有一行 status column='Active',我想要该行,如果不,如果有一行 status='Waiting Approval',我想要那一行,如果有一行 status='Canceled',我想要那一行,等等...我可以在没有子选择的情况下执行此操作吗?有一个子选择?

4

3 回答 3

4

利用:

LEFT JOIN (SELECT *
           FROM OtherTable
           WHERE <criteria>
           ORDER BY CASE status
                        WHEN 'Active' THEN 1
                        WHEN 'Waiting Approval' THEN 2
                        WHEN 'Canceled' THEN 3
                        ...
                    END
           LIMIT 1) other
于 2013-10-13T21:25:58.420 回答
1

在某些情况下(但不是在所有情况下),您可以在没有子选择的情况下进行操作。您将需要GROUP BY表 A 中的唯一字段,通常是 ID。这可确保您从表 B 中仅获得一个(或没有)行。但是,选择所需的行是棘手的部分。您需要一个聚合函数,例如 MAX()。如果 B 中的字段是数字,那很容易做到。如果没有,您可以在 B 中的字段上应用一些 SQL 函数来计算诸如分数之类的排序依据。例如,Active可能对应于比Cancelled等更高的值。这将在没有子选择的情况下工作,并且在大数据集上可能更快。

使用子选择很容易做到。您可以使用 Barmar 的解决方案,或者,如果您只需要 B 中的一个特定字段,您也可以将子选择放在外部查询的 SELECT 子句中。

于 2013-10-13T21:35:08.297 回答
0

我需要跟进一些额外的测试,以确保这能实现我的目标——但我认为我已经使用 travelboy 的 group by query 建议结合 barmar 的案例逻辑(希望我可以拆分答案)来做到这一点。这是查询:

SELECT 
  beds.bed_id,
  beds.bedstatus,
  beds.position as bed_position,
  rooms.room_id,
  rooms.room,
  wings.wing_id,
  wings.name as wing_name,
  buildings.building_id,
  buildings.name as building_name,
  assignments.assignment_id,
  assignments.student_id,
  assignments.assign_dt,
  assignments.assigned_by,
  assignments.assignment_status,
  assignments.expected_arrival_dt as arrival_dt,
  assignments.room_charge_type,
  MIN(CASE assignments.assignment_status
         WHEN 'Active' THEN 1
         WHEN 'Waiting Approval' THEN 2
         WHEN 'Canceled' THEN 3
       END),
  students.first_name,
  students.last_name,
  meal_plans.name as meal_plan_name,
  room_rates.rate_name
FROM
  beds
LEFT JOIN 
  rooms ON (beds.room_id = rooms.room_id)
LEFT JOIN
  wings ON (rooms.wing_id = wings.wing_id)
LEFT JOIN
  buildings ON (wings.building_id = buildings.building_id)

LEFT JOIN assignments
  ON ((assignments.bed_id=beds.bed_id) AND (term_id = 28))
LEFT JOIN
  students ON (assignments.student_id = students.student_id)
LEFT JOIN
  meal_plans ON (assignments.meal_plan_id = meal_plans.meal_plan_id)
LEFT JOIN
  room_rates ON (assignments.room_rate_id = room_rates.room_rate_id)
WHERE
  (
    (rooms.room IS NOT NULL) AND
    (rooms.assignable = 1) AND
    (buildings.active = 1)
  )
GROUP BY
  bed_id
ORDER BY rooms.room;
于 2013-10-20T08:58:10.317 回答