子查询和联盟

时间:2015-04-29 05:03:40

标签: mysql database subquery union

我有下一个mysql表


    CREATE TABLE IF NOT EXISTS `my_app`.`hotel` (
      `id` INT NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(45) NOT NULL,
      `destination_id` INT NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `idx_name` (`name` ASC),
      INDEX `fk_hotel_destination1_idx` (`destination_id` ASC),
      CONSTRAINT `fk_hotel_destination1`
        FOREIGN KEY (`destination_id`)
        REFERENCES `my_app`.`destination` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB


    CREATE TABLE IF NOT EXISTS `my_app`.`hotel_alias` (
      `id` INT NOT NULL AUTO_INCREMENT,
      `hotel_id` INT NOT NULL,
      `name` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `idx_name` (`name` ASC),
      INDEX `fk_hotel_alias_hotel_idx` (`hotel_id` ASC),
      CONSTRAINT `fk_hotel_alias_hotel`
        FOREIGN KEY (`hotel_id`)
        REFERENCES `my_app`.`hotel` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB


    CREATE TABLE IF NOT EXISTS `my_app`.`destination` (
      `id` INT NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `idx_name` (`name` ASC))
    ENGINE = InnoDB


    CREATE TABLE IF NOT EXISTS `my_app`.`place` (
      `id` INT NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(45) NOT NULL,
      `destination_id` INT NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `idx_name` (`name` ASC),
      INDEX `fk_place_destination1_idx` (`destination_id` ASC),
      CONSTRAINT `fk_place_destination1`
        FOREIGN KEY (`destination_id`)
        REFERENCES `my_app`.`destination` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB

我想创建一个视图来填充jquery自动完成,所以我做了下一个查询


    SELECT name, 'hotel' AS type, (SELECT id FROM destination WHERE hotel.destination_id = destination.id) AS destination_id FROM hotel 
    UNION  
    SELECT name, 'place' AS type, (SELECT id FROM destination WHERE place.destination_id = destination.id) AS destination_id FROM place
    UNION 
    SELECT name, 'alias' AS type, (SELECT destination.id FROM destination,hotel WHERE hotel_alias.hotel_id = hotel.id AND hotel.destination_id = destination.id) AS destination_id FROM hotel_alias

返回以下结果


    |name                       |type   |destination_id
    --------------------------------------------------- 
    |hotel casa maya            |hotel  |1
    |sandos caracol             |hotel  |2
    |cabañas tulum              |hotel  |3
    |sandos luxury              |hotel  |1
    |ocean spa                  |hotel  |1
    |sandos playacar            |hotel  |2
    |walmart                    |place  |1
    |walmart                    |place  |2
    |centro                     |place  |3
    |campo de golf pok-ta-pok   |place  |1
    |sandos beach scape         |alias  |2
    |sunset spa                 |alias  |1

结果是正确的,但我想知道我是否正确使用“子查询”和“联合”,或者是否有更好的方法通过优化查询生成相同的结果?

格拉西亚斯!

3 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

您可以通过首先执行联合,然后内部连接到目标表来确保目标存在且有效,从而获得所需的结果而无需借助多个从属子查询。

select q.name, q.type, d.id  
  from (        
    select name, 'hotel' as type, destination_id as d_id
      from hotel
    union all
    select name, 'place' as type, destination_id as d_id
      from place
    union all
    select ha.name, 'alias' as type, destination_id as d_id
      from hotel_alias ha
        inner join hotel h
          on ha.hotel_id = h.id
   ) q
   inner join destination d
     on q.d_id = d.id

没有依赖子查询,union all可以避免不同的清除,与查询结果相同。 demo here

由于您希望将其用作视图,因此您可以将查询扩展为:

select hotel.name, 'hotel' as type, destination_id as d_id
  from hotel
    inner join destination d1
      on hotel.destination_id = d1.id
union all
select place.name, 'place' as type, destination_id as d_id
  from place
    inner join destination d2
      on place.destination_id = d2.id
union all
select ha.name, 'alias' as type, destination_id as d_id
  from hotel_alias ha
    inner join hotel h
      on ha.hotel_id = h.id
    inner join destination d3
      on h.destination_id = d3.id

或者使用原始查询,将其拆分为两个视图

create view v1 as 
  select name, 'hotel' as type, destination_id as d_id
    from hotel
  union all
    select name, 'place' as type, destination_id as d_id
      from place
  union all
    select ha.name, 'alias' as type, destination_id as d_id
      from hotel_alias ha
        inner join hotel h
          on ha.hotel_id = h.id

然后

create view YOUR_VIEW as
  select v1.name, v1.type, d.id
    from v1
      inner join destination d
        on v1.d_id = d.id
  order by type, name;

然后

select * from YOUR_VIEW

会为您提供所需的结果。

updated fiddle显示以上所有选项。

答案 2 :(得分:-1)

无论你为获得结果做了什么都是正确的。没有任何其他方法可以产生相同的结果。