是否有更有效的方法来构建没有联合和重复语句的查询?

时间:2013-01-11 21:39:22

标签: mysql

我有一个查询,基本上找到了符合特定产品资格的所有会员及其家人。每个家庭成员都列在一行中,即使他们属于同一个家庭。我们使用注释的MySQL。

例如(实际返回的所有数据的一小部分样本):

ID  | familyid |  firstname | lastname | address      | city      | relationship
==============================================================================
1   |    1     |   john     |  davis   | 942 James Ln | cityplace | primary
2   |    1     |   suzy     |  davis   | 942 James Ln | cityplace | spouse
3   |    2     |   andrew   |  smith   | 444 A Rd     | new york  | primary
4   |    3     |   Mike     |  lewis   | 123 Street   | dallas    | primary
5   |    3     |   Donna    |  lewis   | 123 Street   | dallas    | child
1   |    3     |   Jamie    |  lewis   | 123 Street   | dallas    | child

上表中的(组成)数据来自两个表:

  
      
  1. 主要信息(包含有关会员和地址的所有一般信息)
  2.   
  3. 家庭信息(包含配偶和子女的姓名和性别信息)
  4.   

为简单起见,我们假设这些表中包含的唯一信息如下:

构件

ID | familyid | firstname | lastname | address | city
-----------------------------------------------------

家族

ID | familyid | firstname | lastname | type | gender
------------------------------------------------------

我们系统中的成员可以拥有他们选择的几种产品(信息中心在一个单独的表中)。不幸的是,我知道构建上述语句的唯一方法是两次基本上选择相同的信息,然后执行UNION ALL语句,如下面的示例语句:

SELECT r.* FROM (
  SELECT familyid, firstname, lastname, address, city, 'primary'
  FROM member
 UNION ALL
  SELECT a.familyid, b.firstname, b.lastname, a.address, a.city, IF(b.type = 1, 'spouse', 'child')
  FROM member a
  JOIN family b ON (a.familyid = b.familyid)
) r

这已经有点混乱,但真实的'当我开始将其他几个表格加入“' name'已收集的信息。例如,我可以在整个查询中添加一个join语句,仅显示已选择HBO电视服务的成员或家庭:

after last statement: JOIN channels c ON (r.familyid = c.familyid)

这将清除之前选择的语句中没有HBO的所有成员,但如果我想选择HBO的子部分(例如,那些只有成员版本而不是整个家庭版本的人)。这些后续查询基本上迫使我两次完全相同的调用只返回稍微不同的信息。

SELECT r.* FROM (
  SELECT familyid, firstname, lastname, address, city, 'primary'
  FROM member m
  JOIN channels c ON (m.familyid = c.familyid)
  WHERE c.name = "HBO" and c.memtype = "member only"
 UNION ALL
  SELECT a.familyid, b.firstname, b.lastname, a.address, a.city, IF(b.type = 1, 'spouse', 'child')
  FROM member a
  JOIN family b ON (a.familyid = b.familyid)
  JOIN channels c ON (b.familyid = c.familyid)
  WHERE c.name = "HBO" and c.memtype = "family"
) r

有没有办法更好地优化这些陈述? MySQL在这件事上只是SOL吗?

注意: 这些表格按原样进行了标准化,因此请不要建议对其进行改进。此特定查询仅适用于每月自动生成一次的报告(非常不常见)。我只是试图找出是否有可能避免使用模式的Union语句。架构无法修改。

3 个答案:

答案 0 :(得分:2)

您似乎正在使用member表来存储家庭的“主要”成员和家庭住址,并使用family表来存储有关其他人的信息。这似乎设计得不是很好,名字也没有很好地选择。

建议:将所有“主要”成员添加到family表格,并使用新的第三个type

INSERT INTO family
  (family_id, type, firstname, lastname)
SELECT family_id, 2, firstname, lastname
FROM member ;

然后您可以使用r查询的简单连接:

SELECT a.familyid, b.firstname, b.lastname, a.address, a.city, 
       CASE b.type 
         WHEN 0 THEN 'child'
         WHEN 1 THEN 'spouse'
         WHEN 2 THEN 'primary'
       END AS type
FROM member a
  JOIN family b 
    ON a.familyid = b.familyid ;

您甚至可能会从firstname表中删除lastnamemember列(并且可能会重命名表格以更好地反映其使用情况)。


第二种情况将写成:

SELECT a.familyid, b.firstname, b.lastname, a.address, a.city, 
       CASE b.type 
         WHEN 0 THEN 'child'
         WHEN 1 THEN 'spouse'
         WHEN 2 THEN 'primary'
       END AS type
FROM member a
  JOIN family b 
    ON a.familyid = b.familyid
  JOIN channels c 
    ON b.familyid = c.familyid
WHERE c.name = 'HBO' AND ( b.type <> 2 AND c.memtype = 'family'  
                        OR b.type  = 2 AND c.memtype = 'member only'
                         ) ;

答案 1 :(得分:2)

正如我在评论中提到的,在我看来,使用更灵活的模式(如下所示)更为可行:

family表将假设一个家庭,其中包含来自member的成员。这些成员之间的关系将在member_map中处理。 parent_member_id是可选的,在这种情况下会指示户主。

答案 2 :(得分:0)

我不太确定我是否完全理解这个问题。 (因为我不知道预期的结果集是什么)。 但是,将家庭概念与个人成员分开是个好主意。要做到这一点,Family应该是一个表和家庭成员一个名为Members的单独表。 (这可能很明显,但为了清楚起见)

创建表Family(   Family_ID,   姓,   Family_Address,   。   。   。 )

创建表MEmbers(   会员ID   Is_Primary / 1或0 /,   Member_Name / *扩展为所需的列数,例如 - 名字,姓氏...... * /,   Member_Info / *为性别,年龄...... * / )

然后,您的联接应构建为:家庭加入渠道,以获得具有某种观看模式的家庭和个人会员:家庭加入渠道加入会员。

(这是我对Stackoverflow的第一次评论。我不太清楚如何突出语法...)。我发现它会更加精致。