将多对多关系分组

时间:2014-08-27 15:44:40

标签: mysql sql

我要求根据当时居住的国家/地区将税率映射到某个人。

tbl: person
| p_id | name_first | name_last |
=======++========================
| 1    | john       | smith     |
| 2    | joanne     | smyth     |


            tbl: person_in_country
            | p_id | iso | arrived    |
            ===========================
            | 1    | GB  | 1980-01-01 |
            | 2    | FR  | 1987-03-21 |
            | 1    | FR  | 2003-06-17 |
            | 1    | JP  | 2008-07-02 |
            | 2    | GB  | 2008-10-01 |
            | 1    | GB  | 2009-01-10 |

tbl: country
| iso | ctry_name      |
========================
| GB  | United Kingdom |
| FR  | France         |
| JP  | Japan          |

            tbl: tax_rates
            | iso | tax_rate | tax_date   |
            ===============================
            | GB  | 17.5     | 1970-01-01 |
            | FR  | 15.0     | 1977-03-21 |
            | JP  | 12.0     | 1977-06-17 |
            | FR  | 15.0     | 1994-03-21 |
            | JP  | 18.5     | 2008-07-02 |
            | GB  | 15       | 2008-04-01 |
            | GB  | 20       | 2010-05-01 |

所以我需要包含国家人士和他们在特定时间应该具有的税率的元组。

有些事情:

select p.p_id, p.name_first, p.name_last,
       pic.arrived,
       c.iso, c.ctry_name,
       t.tax_rate
from people p
left join (select * from person_in_country order by arrived desc) pic using (p_id)
left join country c on c.iso = pic.iso
left join (select * from tax_rates order by tax_date desc) t on t.iso = c.iso
where t.tax_date <= NOW()
group by p.pid, pic.arrived, t.tax_date

希望这有意义......并提前多多谢谢

1 个答案:

答案 0 :(得分:1)

实际上,您必须分三步进行查询。首先,您要检索一种&#34;原始数据&#34;使用所有需要的列,连接相关表,无论这些列将用于连接或检索选择的数据。

之后,您必须对数据进行分组,以便仅匹配匹配联接中的最后日期。

最后,您必须再次查询税表以在抵达时的当前纳税日期中检索税。

有可能有一种更简单或更优雅的方式,但这个查询是有效的。根据查询命令检查系统性能。乍一看似乎有点难,但是在采取更细致的外观时并不是这样。 SQL代码:

SELECT 
    c02.iso, 
    c02.p_id, 
    c02.name_first, 
    c02.name_last, 
    c02.ctry_name, 
    c02.arrived, 
    c02.mtax_date, 
    tax_rates.tax_rate

FROM (
    SELECT 
        c01.iso, 
        c01.p_id, 
        c01.name_first, 
        c01.name_last, 
        c01.ctry_name, 
        c01.arrived, 
        Max(c01.tax_date) AS mtax_date
    FROM (

        SELECT 
            country.iso, 
            person.p_id, 
            person.name_first, 
            person.name_last, 
            country.ctry_name, 
            person_in_country.arrived, 
            tax_rates.tax_date
        FROM 
            tax_rates 
        INNER JOIN (
                country 
        INNER JOIN (
                person 
        INNER JOIN 
                person_in_country 
            ON 
                person.p_id = person_in_country.p_id
               )
            ON 
                country.iso = person_in_country.iso
               ) 
            ON 
                tax_rates.iso = person_in_country.iso
            GROUP BY 
                country.iso, 
                person.p_id, 
                person.name_first, 
                person.name_last, 
                country.ctry_name, 
                person_in_country.arrived, 
                tax_rates.tax_date
            HAVING (((tax_rates.tax_date)<=[arrived]))
        ) as c01
    GROUP BY 
        c01.iso, 
        c01.p_id, 
        c01.name_first, 
        c01.name_last, 
        c01.ctry_name, 
        c01.arrived
    ) as c02 

INNER JOIN 
    tax_rates ON (
            c02.mtax_date = tax_rates.tax_date
             ) 
             AND 
             (
            c02.iso = tax_rates.iso
              );

输出:

iso p_id    name_first  name_last   ctry_name   arrived     mtax_date   tax_rate
GB  1   john        smith       United Kindom   01/01/1980  01/01/1970  18
FR  2   joanne      smyth       France          21/03/1987  21/03/1977  15
FR  1   john        smith       France          17/06/2003  21/03/1994  15
JP  1   john        smith       Japan           02/07/2008  02/07/2008  18
GB  1   john        smith       United Kindom   10/01/2009  01/04/2008  15
GB  2   joanne      smyth       United Kindom   01/10/2008  01/04/2008  15