2014-08-27 7 views
0

У меня есть требование сопоставить ставку налога с человеком в зависимости от страны, в которой проживал человек в то время.Групповые отношения многих-ко-многим-многим

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

Если вы хотите, рассмотрим следующие этой простой двухступенчатой ​​курс действий: 1. Если вы еще не сделали этого, обеспечить надлежащее DDLS (и/или sqlfiddle), чтобы мы могли легче воспроизвести проблему. 2. Если вы еще этого не сделали, укажите желаемый набор результатов, который соответствует информации, представленной на шаге 1. – Strawberry

ответ

1

На самом деле, вы должны сделать запрос в основном в три этапа. Сначала вы получите «необработанные данные» со всеми желаемыми столбцами, соединяя связанные таблицы, независимо от того, какие из этих столбцов будут использоваться для соединения или для извлечения выбранных данных.

После этого вам необходимо сгруппировать данные, чтобы включить только последние даты из соответствующего соединения.

Наконец, вы должны снова запросить налоговую таблицу, чтобы получить налог в налоговую дату, действующую в момент прибытия.

Возможно, что есть более простой или элитарный способ сделать это, но этот запрос работает. Проверьте производительность системы в зависимости от демонов запроса. Кажется, это немного сложно с первого взгляда, но это не то, что нужно делать более осторожно. 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 
+0

Еще один совет: SQL также является языком, старайтесь быть как можно более indentfull, как вы можете! ;) – Alex

Смежные вопросы