|  | | 
 
| 
           
             | 
                 
                   | Тема |  "обратното" на join   |  |  | Автор | Masklin (ном) |  | Публикувано | 04.03.08 18:53 |  |  | 
           
 Здравейте.
 
 Представете си две таблици, свързани в съотношение 1:n -  в едната има id и някакви данни, а в другата ключ към първата и нейните си данни; във втората няколко реда могат да имат един и същ външен ключ.
 
 Питането е следното: как да вземем тези редове от първата таблица, към които няма ключ във втората?
 
 Сещам се за един начин, но ми се струва неразумен от гледна точка на производителност:
 select distinct a.* from a, b where a.id != b.a_fkey  
 Предполагам, че решението е очевидно, но не се сещам. Идеи?
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: "обратното" на join  [re: Masklin] |  |  | Автор | wqw (АзСъмЖив) |  | Публикувано | 04.03.08 19:33 |  |  | 
           
 
 -- old-school за single column keys
select      a.*
 from        a
 where       a.pk not in (select a_fkey from b)
 
 -- old-scool за composite keys
 select      a.*
 from        a
 where       not exists (select  *
 from    b
 where   b.a_fkey = a.pk)
 
 -- neo-gamei
 select      a.*
 from        a
 left join   b
 on          a.pk = b.a_fkey
 where       b.pk is null
 (not tested)
 
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  Благодаря
[re: wqw] |  |  | Автор | Masklin (ном) |  | Публикувано | 05.03.08 13:56 |  |  | 
           
 
 
 не бях съобразил, че проверката се прави върху данните от декартовото произведение (т.е. резултата от left join-а), а не в самата таблица. Поради което можеш да правиш ... where b.pk is null
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: Благодаря  [re: Masklin] |  |  | Автор | wqw (АзСъмЖив) |  | Публикувано | 05.03.08 19:59 |  |  | 
           
 Мне е декартовото произведение. Просто по дефиниция OUTER JOIN е INNER JOIN който е UNION ALL с NOT IN така някак:
 
 SELECT a.*, b*
 FROM a
 JOIN b
 ON a.pk = b.a_fkey
 
 UNION ALL
 
 SELECT a.*, NULL, NULL, NULL, ...
 FROM a
 WHERE a.pk NOT IN (SELECT a_fkey FROM b)
 
 Аз лично ползвам old-school аналозите щото са >= бързи от OUTER JOIN-а (това при MSSQL). Чат-пат db-engine-а не може да съобрази, че няма да дублира редове от a заради JOIN-а. Със sub-select винаги се ориентира че резултатът е подмножество на a (логично като няма нищо друго във FROM клаузата:-)).
 
 cheers,
 </wqw>
 
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  composite keys  [re: wqw] |  |  | Автор | Dakota (erotoman) |  | Публикувано | 07.03.08 15:26 |  |  | 
           
 Всъщност и за множество ключове може така:
 
 
 SELECT
a.*
 FROM
 a
 WHERE
 (a.pk1, a.pk2) NOT IN (SELECT a_fkey1, a_fkey2 FROM b);
 
 Но за големи стойности на b, по-добре е другото... в повечето случаи, и пак... прословутото зависи.
 
 Everything louder than everything else...
 Редактирано от Dakota на 07.03.08 15:28. 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: composite keys  [re: Dakota] |  |  | Автор | wqw (АзСъмЖив) |  | Публикувано | 11.03.08 17:21 |  |  | 
           
 MSSQL и Access не разбират от използване на tuples по този начин. Съвсем забравих, че бази данни = MySQL в този форум :-))
 
 cheers,
 </wqw>
 
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: composite keys  [re: wqw] |  |  | Автор | phpGuru (непознат
) |  | Публикувано | 12.03.08 15:13 |  |  | 
           
 амии по скоро ти приемаш за база данни за MSSQL или access
 
 
 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: composite keys  [re: wqw] |  |  | Автор | Dakota (erotoman) |  | Публикувано | 12.03.08 21:13 |  |  | 
           
 Е, това го ползвам в PostgreSQL. За MySQL изобщо не знам дали работи.
 
 А иначе балимааму как е по стандарт.
 
 Everything louder than everything else...
 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: "обратното" на join  [re: wqw] |  |  | Автор | _danitu (аз) |  | Публикувано | 19.03.08 14:52 |  |  | 
           
 Въпросче: трите варианта по-бързи ли ще са от това например и защо
 
 SELECT a.id, a.a1, a.a2
 FROM [а] LEFT JOIN [c] ON a.ID = c.id_a
 GROUP BY a.id, a.a1, a.a2
 HAVING (((Count(c.id))=0));
 
 Сори на автора, че се възползвам от темата ;)
 
 
 Редактирано от _danitu на 19.03.08 14:54. 
 
 |  |  |  
             | 
                 
                   | Тема |  Re: "обратното" на join  [re: _danitu] |  |  | Автор | Dakota (erotoman) |  | Публикувано | 19.03.08 20:46 |  |  | 
           
 Е, това е най-лошият вариант дотук. Изпускаш питомното (WHERE), за да гониш дивото (HAVING).
 
 Everything louder than everything else...
 
 
 |  |  |  |  
 
 |   | 
 |