SQL Joins и MS Access - Как да комбинирам множество таблици в една?

Имам четири таблици в Access 2010, всяка с един и същ първичен ключ. Бих искал да обединя всички данни във всичките четири таблици в една таблица с колони за всяка стойност, обвързана с първичния ключ над всички таблици. Така например:

Table1

ID   Value1

1    10       
2    7
3    4
4    12

Table 2

ID   Value2

1    33
2    8
6    19
7    4

Table 3

ID   Value3

1    99
2    99
5    99
7    99

Бих искал да създам:

Table 4

ID  Value1  Value2  Value3

1   10      33      99
2   7       8       99
3   4
4   12
5           99
6           19      
7           4       99

Използвам MS Access и знам, че трябва основно да използвам 3 съединения (ляво, дясно, вътрешно), за да получа пълно съединение, но не съм съвсем сигурен как да структурирам заявката.

Може ли някой да ми даде примерен SQL код, който да ме насочи в правилната посока как да произведа този резултат?

Ето какво имам досега. Това комбинира всички таблици, но изглежда, че все още ми липсват някои данни. Направих ли нещо грешно:

SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry LEFT JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) LEFT JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) LEFT JOIN OFSP ON Medicare.cptcode = OFSP.cptcode
UNION
SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry RIGHT JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) RIGHT JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) RIGHT JOIN OFSP ON Medicare.cptcode = OFSP.cptcode
UNION
SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry INNER JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) INNER JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) INNER JOIN OFSP ON Medicare.cptcode = OFSP.cptcode;

person Victor Brunell    schedule 03.07.2014    source източник
comment
Опитахте ли да го гугълнете?   -  person Alexandre Santos    schedule 03.07.2014
comment
Да, но не мога да намеря нищо, което да отговаря точно на това. Намирам известна информация за използването на всичките три клаузи за присъединяване, но клаузата ON след клаузата за присъединяване изглежда изисква да имам някои полета, които са еднакви, но бих искал да изтегля всички полета, дори ако няма съвпадение в друга таблица, като запис 5 от примера в моя въпрос.   -  person Victor Brunell    schedule 03.07.2014


Отговори (3)


Какво ще кажете за това?

SELECT id
, max(v1) as value1
, max(v2) as value2
, max(v3) as value3
FROM 
(
    select id
    , value1 as v1
    , iif(true,null,value1) as v2
    , iif(true,null,value1) as v3 
    from Table1

    union 

    select id, null , value2 , null  from Table2

    union 

    select id, null , null , value3 as v3 from Table3
)
group by id
order by id

Как работи:

  • Вместо да правя обединяване, поставям всички резултати в една „таблица“ (моята подзаявка), но със стойност1, стойност2 и стойност3 в техните собствени колони и задавам нула за таблиците, които нямат тези колони.

  • Изявленията iif в първата заявка трябва да кажат, че искам v2 и v3 да бъдат от същия тип данни като v1. Това е хитър хак, но изглежда работи (за съжаление access работи с типа от първия израз в заявката и кастингът сclng(null) не работи). Те работят, защото резултатът от iif трябва да бъде от същия тип като последните два параметъра и само последният параметър има тип, така че това се извежда от това; докато първият параметър е верен означава, че върнатата стойност ще бъде само вторият параметър.

  • След това външната заявка свива тези резултати до един ред на id; тъй като полетата със стойност са по-големи от null и имаме най-много едно поле със стойност за id, получаваме тази стойност за тази колона.

Не съм сигурен как се сравнява производителността с начина, по който се прави това в статията на MS, но ако използвате достъп, подозирам, че имате други неща, за които да се тревожите ;).

SQL Fiddle: http://sqlfiddle.com/#!6/6f93b/2 ( За SQL Server, тъй като Access не е наличен, но се опитах да го направя възможно най-подобен)

person JohnLBevan    schedule 03.07.2014
comment
Какво представляват id, v1, v2 и v3? - person Victor Brunell; 05.07.2014
comment
@Caulibrot: те са дефинирани в подзаявката. Те представляват съответно Стойност1, Стойност2 и Стойност3; Нарекох ги v# вместо value# за краткост и за да избегна объркване с действителните имена на колони; т.е. така че можете лесно да разберете къде изтеглям данни директно от таблицата срещу това къде правя нещо малко по-различно (в този случай изтеглям стойността на полето или използвам null, когато таблицата източник не съдържа тази колона). - person JohnLBevan; 05.07.2014

Създайте обединение на всички идентификационни номера от всички таблици, като по този начин получавате колоната с id в таблица4. След това капсулирайте това обединение в подизбор (ids) и създайте леви съединения между този подизбор (родителското присъединяване) и table1, table2, table3 (детелното присъединяване). След това изберете това, от което се нуждаете...

SELECT 
ids.id, 
t1.Value1, 
t2.Value2, 
t3.Value3
FROM ((
(select id from table1 
union 
select id from table2
union 
select id from table3)  AS ids 
LEFT JOIN Table1 AS t1 ON ids.id = t1.ID) 
LEFT JOIN Table2 AS t2 ON ids.id = t2.ID) 
LEFT JOIN Table3 AS t3 ON ids.id = t3.ID;
person nelucon    schedule 04.07.2014
comment
Хубаво е много по-добре от използването на max, но може да искате да обясните какво правите. - person Conrad Frix; 04.07.2014
comment
Имах предвид, че трябва да редактирате отговора си, за да обясните какво правите. И по-специално защо е по-добър от приетия отговор. - person Conrad Frix; 08.07.2014
comment
Технически трябва да доведе до същия резултат, защото Id е първичен ключ. Но това може да е по-бързо, защото не включва никаква агрегатна функция. - person nelucon; 08.07.2014

Ето вариант на отговора на JohnLBevan, който ще работи, ако [Value1], [Value2] и [Value3] са от различни типове. Например, с

Маса 1

ID  Value1
--  ------
 1      10
 2       7
 3       4
 4      12

Таблица 2

ID  Value2      
--  ------------
 1  thirty-three
 2  eight       
 6  nineteen    
 7  four        

Таблица3

ID  Value3    
--  ----------
 1  1999-01-01
 2  1999-01-01
 5  1999-01-01
 7  1999-01-01

заявката

SELECT ID, MAX(v1) AS Value1, MAX(v2) AS Value2, MAX(v3) as Value3
FROM (
        SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
        FROM (SELECT COUNT(*) FROM Table1)
    UNION ALL
        SELECT ID, Value1 AS v1, NULL AS v2, NULL AS v3
        FROM Table1
    UNION ALL
        SELECT ID, NULL AS v1, Value2 AS v2, NULL AS v3
        FROM Table2
    UNION ALL
        SELECT ID, NULL AS v1, NULL AS v2, Value3 AS v3
        FROM Table3
)
WHERE ID > 0
GROUP BY ID

се завръща

ID  Value1  Value2        Value3    
--  ------  ------------  ----------
 1      10  thirty-three  1999-01-01
 2       7  eight         1999-01-01
 3       4                          
 4      12                          
 5                        1999-01-01
 6          nineteen                
 7          four          1999-01-01

Обяснение:

Първата част от подзаявката UNION създава единичен ред с фиктивни стойности, за да гарантира, че резултатът от UNION има правилните типове колони

SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
FROM (SELECT COUNT(*) FROM Table1)

се завръща

ID  v1  v2  v3        
--  --  --  ----------
 0   0      2001-01-01

Останалата част от подзаявката UNION добавя действителните редове от всяка таблица

    SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
    FROM (SELECT COUNT(*) FROM Table1)
UNION ALL
    SELECT ID, Value1 AS v1, NULL AS v2, NULL AS v3
    FROM Table1
UNION ALL
    SELECT ID, NULL AS v1, Value2 AS v2, NULL AS v3
    FROM Table2
UNION ALL
    SELECT ID, NULL AS v1, NULL AS v2, Value3 AS v3
    FROM Table3

давайки ни

ID  v1  v2            v3        
--  --  ------------  ----------
 0   0                2001-01-01
 1  10                          
 2   7                          
 3   4                          
 4  12                          
 1      thirty-three            
 2      eight                   
 6      nineteen                
 7      four                    
 1                    1999-01-01
 2                    1999-01-01
 5                    1999-01-01
 7                    1999-01-01

Външната заявка за агрегиране изключва първия ред с фиктивните стойности (WHERE ID > 0), дава ни един ред за ID (GROUP BY ID) и използва функцията MAX(), за да върне стойност, ако има такава (или Null, ако няма).

ID  Value1  Value2        Value3    
--  ------  ------------  ----------
 1      10  thirty-three  1999-01-01
 2       7  eight         1999-01-01
 3       4                          
 4      12                          
 5                        1999-01-01
 6          nineteen                
 7          four          1999-01-01
person Gord Thompson    schedule 03.07.2014
comment
Това е подобно на това, което ми трябва, но наистина не разбирам синтаксиса. Защо използвате MAX и защо избирате 0 като ID? И откъде идват стойностите v1, v2, v3? - person Victor Brunell; 05.07.2014
comment
Ако имам няколко таблици с едно и също име за стойност, мога ли да променя v1 да бъде нещо като table1.v1 и v2 да бъде table2.v2? - person Victor Brunell; 05.07.2014