3

我有一个数据库,其中包括以下两个表:

classes是一个简单的表格,在课程表中每个班级都有一行。

sessions是一个表格,描述了每个班级遇到的日期和时间,其中每一行都能够表达如下概念:

“周二 | 1 月 22 日至 3 月 5 日 | 6-9pm”
“周二和周四 | 1 月 22 日至 3 月 7 日 | 6-9pm”
“周一至周四 | 1 月 21-24 日 | 3-6pm”
“周六 | 3 月 9 日 | 9am-下午4点”

等等。

sessions中的每一行保证至少有一行classes,并且对于某些类,可能有两个或更多关联的会话行。

目前,我正在使用两个不同的查询来获取与特定条件集匹配的类的类和会话信息,如下所示:

select c.class_id, c.title, c.instructor, c.num_seats, c.price
  from classes c
  join classes_by_department cbd 
    on (cbd.class_id = c.class_id)
  join /* several other tables */
    on /* several other join conditions */
 where cbd.department_id = '{$dept_id}'
   and /* several other qualifying conditions */
;

还有这个:

select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
  from sessions s
  join classes c
    on (c.class_id = s.class_id)
  join classes_by_department cbd
    on (cbd.class_id = s.class_id) 
  join /* the same other tables */
    on /* the same other join conditions */
 where cbd.department_id = '{$dept_id}'
   and /* the same other qualifying conditions */
;

这工作得很好,而且——至少在当前的应用程序中——表不够大,流量也不够大,两个查询都不是问题。尽管如此,它让我觉得有点浪费,我想知道是否没有办法更好地利用第一个查询已经完成的工作来执行第二个查询(而不是相当于运行相同的查询两次和只是选择不同的列)。

当然,我意识到我可以从单个查询(第二个)中选择所有相关列classessessions但我喜欢这样一个事实,即在当前方法中,第一个查询为每个符合条件的类提供一行,而不是作为许多行,因为该类具有会话记录。如果合并查询,我将需要重组处理查询结果的现有逻辑。(是的,我知道,哇……)

我想到的一个解决方案是将第一个查询返回的所有 s 收集class_id到一个向量中(因为无论如何我都必须遍历这些结果),然后将该向量的内容格式化为子句的值列表IN的内容,因此第二个查询将简单地变为:

select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
  from sessions s
 where s.class_id in (/* value-list */);

我不太担心这种解决方案的可扩展性,因为我知道大型 SQL 查询没什么大不了的。另外,它可以利用在sessions.class_id.

但是......嗯......对于那些希望提高他的 SQL 能力的人来说,这并不是很令人满意,我会坦率地承认这是相当初级的。它感觉不优雅,而且不是很“SQL-ish”,或者任何与Pythonic等价的 SQL是什么。

任何人都可以提出更合适的建议吗?

4

2 回答 2

1

做你想做的事的规范方法是使用视图。将您的第一个查询定义为:

create view vw_MyClasses as
    select c.class_id, c.title, c.instructor, c.num_seats, c.price, cbd.department_id
    from classes c
         join classes_by_department cbd 
         on (cbd.class_id = c.class_id)
         join /* several other tables */
         on /* several other join conditions */
   where /* several other qualifying conditions */

那么你的类查询将是:

select *
from vw_MyClasses
where department_id = '{$dept_id}'

然后,您的第二个查询可以是:

 select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
 from sessions s
 where s.class_id in (select class_id from vw_MyClasses 
                                      where department_id = '{$dept_id}');

或者,在 MySQL 中什么可能更有效:

 select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
 from sessions s
 where exists (select 1 from vw_MyClasses mc where mc.class_id = s.class_id limit 1)

这样做是有充分理由的。在多个查询中重复这样的逻辑成为维护的噩梦。当您在一处修改逻辑时,很容易忘记在所有地方进行修改。有时,视图是不够的,因此您可能需要使用用户定义的函数,如此所述。

此外,如果标准非常有用,您可能希望在类表中放置标志以识别它们。这需要以某种方式维护它们,例如每晚更新或使用触发器。

于 2012-12-28T15:11:08.440 回答
0

老实说,我不会打扰。首先,从您告诉我们的内容来看,它工作得很好,对我来说似乎相当优雅。其次,如果没有理由在第二个查询中带回额外数据,则不要这样做。第三,也是迄今为止最重要的一点是,就目前的情况而言,很容易理解正在发生的事情。您可能并不总是唯一一个试图破译这一点的人,并且其他人可以阅读代码很重要。过于复杂的 SQL 查询并不好。

我认为这很好,而且它的 SQL 风格很好。

于 2012-12-28T08:17:26.147 回答