【问题标题】:How to find the value of a column based on a value of another column?如何根据另一列的值查找一列的值?
【发布时间】:2017-04-12 08:25:45
【问题描述】:

我有一个像这样建模的简单地铁线路系统:

  • 一条线路有多站。
  • 每个车站都有时间表。
  • 时间表包含一些时间信息和一个方向,该方向指示时间信息用于线路的哪个方向。

我的问题是,给定一个时间表,我如何找到属于那个方向的线路的终点站?

我的表格结构如下:

CREATE TABLE schedule (
    id serial PRIMARY KEY,
    to_start boolean,
    start_time time,
    end_time time,
    station_id REFERENCES station
);

CREATE TABLE station (
    id serial PRIMARY KEY,
    name varchar,
    order integer,
    line_id integer REFERENCES line
);

CREATE TABLE line (
    id serial PRIMARY KEY,
    name varchar
);

如果schedule.to_starttrue,则表示方向指向车站,顺序为1falsemax(order)

这里是一些示例数据:

时间表

 id | to_start | start_time | end_time | station_id 
----+----------+------------+----------+------------
  1 | f        | 06:02:00   | 22:02:00 |          2
  2 | t        | 06:35:00   | 23:07:00 |          2

站台表

 id |     name     | order  | line_id 
----+--------------+--------+---------
  1 | Station A    |      1 |       1
  2 | Station B    |      2 |       1
  3 | Station C    |      3 |       1
  4 | Station D    |      1 |       2

折线表

 id |  name  
----+--------
  1 | Line 1 
  2 | Line 2 

因此,如果给定一个schedule.id 值,例如1,我如何找到对应的station.name,它应该是Station C(因为该时间表是id 为2 的车站,属于id 为的线路1,由于to_startfalse,所以它指向行尾,应该是Station C)?

我使用 postgresql,我最初的尝试依赖于多次连接到数据库,在这种情况下,我首先根据给定的 id 选择时间表,保存其 to_startstation_id,然后使用保存station_id,保存它的line_id,根据to_start的值,我要么选择带有line_id的电台和1order,要么先找到max(order),然后选择带有@的电台987654352@ 和最大订单。

感觉真的很麻烦,不让postgresql做最好的优化。

有没有办法用一个 sql 做到这一点?

【问题讨论】:

  • Edit您的问题并添加一些示例数据和基于该数据的预期输出。 Formatted textno screen shotsedit 您的问题不要在 cmets 中发布代码或其他信息。
  • @a_horse_with_no_name 感谢您的建议。已编辑。
  • @hgl 到目前为止你尝试了什么?
  • @JohnHC 我在问题的底部提到了它。我没有发布代码,只是描述了逻辑,因为它涉及将结果保存到变量并进行新的查询,这似乎超出了 sql 的范围。

标签: sql database postgresql


【解决方案1】:

这样就可以了:

select   ds.*
from     schedule s
join     station  qs on qs.id = s.station_id
join     station  ds using (line_id)
where    s.id = 1
order by ds."order" * case when s.to_start then 1 else -1 end
limit    1

注意事项:

  • order 是保留关键字,所以将其用作列名是不明智的
  • 你的架构在我看来有点奇怪,f.ex。如果有多条线路穿过它,您需要复制车站

http://rextester.com/OITNB38639

【讨论】:

  • 谢谢。这非常巧妙,感谢您的建议,我在自己的代码中使用了number。我在这里使用order 只是为了使意图更清晰。而对于重复站,你认为应该多对多吗?我个人觉得把这样的站当作不同的站,然后用转接表记录重复似乎更灵活。
  • @hgl 如果你真的区别对待它们,这可能没问题。它甚至可能在某些极端情况下派上用场。但这会使计算转移变得更加困难(如果您需要这样做)。 -- 多对多似乎是合理的。
【解决方案2】:

您可以通过连接来做到这一点。您可以在一个查询中执行多个联接。

SELECT * FROM schedule JOIN station on station.id = schedule.station_id JOIN line line.id = schedule.line_id WHERE sechdule.id = '1'

有关联接的更多信息: https://www.w3schools.com/sql/sql_join.asp

【讨论】:

  • 我很抱歉,但我怀疑它可能就这么简单,你能让解决方案更具体地解决这个问题吗?谢谢。
  • 我更改了我的解决方案以更具体地解决您的问题。
【解决方案3】:

几个 CTE、一个新的 row_number() 和一些可爱的自我连接

with FirstLast as
(
select a1.*, 
       row_number() over(partition by line_id order by a1.order desc) as order2
from Station a1
)
, Stage2 as
(
select a1.id, a1.name, a2.name as FirstStation, a3.name as LastStation
from FirstLast a1
inner join FirstLast a2
  on a1.line_id = a2.line_id
  and a2.order = 1
inner join FirstLast a3
  on a1.line_id = a3.line_id
  and a3.order2 = 1
)
select x.id, 
       x.name, 
       case 
         when z.to_start = 't' then x.FirstStation 
         else x.LastStation 
       end as TheStation
from schedule z
inner join Stage2 x
  on z.station_id = x.id

【讨论】:

    猜你喜欢
    • 2021-07-25
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2021-09-15
    • 1970-01-01
    • 2021-10-11
    • 2014-11-09
    相关资源
    最近更新 更多