簡體   English   中英

是否有更有效的方法來構建沒有聯合和重復語句的查詢?

[英]Is there a more efficient way of building a query without unions and repeating statements?

我有一個查詢,基本上找到有資格獲得特定產品的所有成員及其家人。 每個家庭成員都列在一行中,即使他們屬於同一個家庭。 我們使用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. 家庭信息(包含配偶和子女的姓名和性別信息)

為簡單起見,我們假設這些表中包含的唯一信息如下:

會員

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語句。 架構無法修改。

您似乎使用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 ;

您甚至可以從member表中刪除firstnamelastname列(並且可能重命名表以更好地反映其用法)。


第二種情況將寫成:

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'
                         ) ;

正如我在評論中提到的,在我看來,使用更靈活的架構(如下所示)更為可行:

family表將假設一個家庭,其中包含來自member 這些成員之間的關系將在member_map處理。 parent_member_id是可選的,在這種情況下將指示戶主。

我不太確定我是否完全理解這個問題。 (因為我不知道預期的結果集是什么)。 但是,將家庭概念與個人成員分開是個好主意。 要做到這一點,Family應該是一個表和家庭成員一個名為Members的單獨表。 (這可能很明顯,但為了清楚起見)

創建表Family(Family_ID,Family_Name,Family_Address,...)

create table MEmbers(Member_ID Is_Primary / 1或0 /,Member_Name / *擴展為所需的列數,例如 - 名字,姓氏...... * /,Member_Info / *作為Gender,Age ... * /)

然后,您的聯接應構建為:家庭加入渠道,以獲得具有某種觀看模式的家庭和個人會員:家庭加入渠道加入會員。

(這是我對Stackoverflow的第一次評論。我不太清楚如何突出語法...)。 我發現它會更加精致。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM