Sql 如何优化以下oracle查询,以便仅在一次联接中获取“发件人”和“收件人”国家/地区名称?

Sql 如何优化以下oracle查询,以便仅在一次联接中获取“发件人”和“收件人”国家/地区名称?,sql,oracle,Sql,Oracle,下面是我正在尝试运行的查询 select from_country_id, to_country_id, fromCountry.country_name as from_country_name, to_country_id.country_name as to_country_name from TourDetails t left join country fromCountr

下面是我正在尝试运行的查询

    select 
          from_country_id, 
          to_country_id, 
          fromCountry.country_name as from_country_name, 
          to_country_id.country_name as to_country_name
    from TourDetails t 
    left join country fromCountry on fromCountry.id = t. from_country_id
    left join country toCountry on toCountry.id = t. to_country_id
我有一个tourdetails表,其中保存了from country id和to country id。我还有另一个country表,其中包含country id和country name

现在,当我查询tourdetails表时,我还需要获得国家名称。为此,我两次使用countyry表的左连接


是否有任何方法不必两次加入此国家/地区表,并且仍然可以获取发件人和收件人国家/地区的国家/地区名称?

即使您无法优化查询,也可以优化查询的执行。
您应该检查查询的解释计划,如果它使用嵌套循环,则可能值得通过
/*+USE_hash(country)*/

强制哈希,因为内部联接有时比左联接运行得快得多。在对数据强制执行引用完整性的情况下,内部联接和左联接将产生相同的结果。引用完整性意味着外键的每个实例都引用引用表中的现有行


DBMS可以通过数据定义中声明的约束来强制实现引用完整性。有时可行的另一种方法是在加载新数据的过程中强制执行引用完整性。让DBMS强制执行引用完整性通常是可取的

它归结为基于tuple([from,to]在tour中)检索国家详细信息(名称)

据我所知,它可能与存在的
有关。请看看下面的一个是否适合您

模式:

create table country (
  country_id varchar2(10)
);

create table tour
(
  from_country_id varchar2(10),
  to_country_id varchar2(10)
);
数据:

解决方案本身:

select
  country_from.country_id from_, 
  country_to.country_id to_ 
from 
  country country_from,
  country country_to
where exists
  (select
     from_country_id, 
     to_country_id
   from tour 
   where 
     from_country_id = country_from.country_id 
    and 
     to_country_id = country_to.country_id)

无需内部联接:-)

您可以使用一个联接来完成此操作,但代价是联接条件中有一个
(或
中的
),并且代码可能不太清晰:

select t.from_country_id,
    t.to_country_id,
    max(case when c.id = from_country_id then c.country_name end)
        as from_country_name,
    max(case when c.id = to_country_id then c.country_name end)
        as to_country_name
from tourdetails t
join country c on c.id = t.from_country_id or c.id = t.to_country_id
group by t.from_country_id, t.to_country_id;

这和拥有两个连接之间可能没有太大的性能差异,您需要进行测试来检查。取决于您在本例中所说的“优化”是什么意思。我想这可能更像是一个风格问题——在减少连接数量和更复杂地处理返回数据之间进行权衡。

@Nikola Markovinović。所以我必须这样做?我是说我做这件事的方式。是的。这是我们有表别名的原因之一。并且没有理由不根据您的要求加入两次。我能想到的唯一替代方法是编写两个函数,GetFromCountry(TourDetails.ID)和GetToCountry(TourDetails.ID)。每个函数将从TourDetails表中的ID中获取国家名称。“不过,在这种情况下,麻烦可能比它的价值还要多。”托比说。我之所以尝试一些更好的解决方案,是因为我会有更多的(实际上是7到8个)其他表,比如country,我需要离开join来获取它们的名称,例如Region(from和to)、Agent(from和to)等。如果我有这么多的join,会不会使查询变慢?对不起,我没有理解您想要说的内容(Oracle optimizer创建了一个如何运行sql脚本的计划。在某些情况下,优化器使用了错误的策略,但您可以通过向sql添加提示来覆盖它。有关解释计划的更多信息:@zoltanamori我认为现在开始考虑提示还为时过早。(此外,您需要使用表别名,而不是实际的表名。)
select t.from_country_id,
    t.to_country_id,
    max(case when c.id = from_country_id then c.country_name end)
        as from_country_name,
    max(case when c.id = to_country_id then c.country_name end)
        as to_country_name
from tourdetails t
join country c on c.id = t.from_country_id or c.id = t.to_country_id
group by t.from_country_id, t.to_country_id;