sybase - значения из одной таблицы, которых нет в другой, на противоположных концах соединения из 3 таблиц - PullRequest
0 голосов
/ 17 апреля 2010

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

3 таблицы:

Таблица A - знаки для компании

sign_pk (уникальный) | company_pk | sign_description
1 -------------------- 1 ---------------- маленький
2 -------------------- 1 ---------------- большой
3 -------------------- 2 ---------------- средний
4 -------------------- 2 ---------------- jumbo
5 -------------------- 3 ---------------- баннер

Таблица B - местонахождение компании

company_pk | company_location (уникальный)
1 ------ | ------ 987
1 ------ | ------ 876
2 ------ | ------ 456
2 ------ | ------ 123

таблица C - знаки в местах (это немного натянуто, но в каждом ряду может быть 2 знака, и это отношение один ко многим от местоположения компании до знаков в местах)

company_location | front_sign | back_sign
987 ------------ 1 ------------ 2
987 ------------ 2 ------------ 1
876 ------------ 2 ------------ 1
456 ------------ 3 ------------ 4
123 ------------ 4 ------------ 3

Итак, a.company_pk = b.company_pk и b.company_location = c.company_location. То, что я хочу попытаться найти, это как запросить и получить обратно, что sign_pk 5 не находится ни в каком месте. Запросить каждый sign_pk для всех значений front_sign и back_sign немного нецелесообразно, поскольку во всех таблицах миллионы строк. Таблица a проиндексирована для sign_pk и company_pk, таблица b - для обоих полей, а таблица c - только для местоположений компании. Я пытаюсь написать это по принципу «каждый знак принадлежит компании, поэтому найдите знаки, которые не являются передним или задним знаком в любом месте, принадлежащем компании, связанной с этим знаком».

Мой первоначальный план был:
Select a.sign_pk<br> from a, b, c<br> where a.company_pk = b.company_pk<br> and b.company_location = c.company_location<br> and a.sign_pk *= c.front_sign<br> group by a.sign_pk having count(c.front_sign) = 0

просто чтобы сделать передний знак, а затем повторить для заднего, но это не сработает, потому что c является внутренним членом внешнего соединения, а также внутреннего соединения.

Все это довольно запутанно, но если кто-то сможет понять это, я буду вашим лучшим другом.

Ответы [ 3 ]

1 голос
/ 17 апреля 2010

Как насчет этого:

  SELECT DISTINCT sign_pk
    FROM table_a
   WHERE sign_pk NOT IN
    (   
      SELECT DISTINCT front_sign sign
        FROM table_c
       UNION
      SELECT DISTINCT rear_sign sign
       FROM  table_c
    )
0 голосов
/ 16 ноября 2011

Я бы хотел создать временную таблицу для внутреннего соединения, а затем для внешнего соединения. Но это действительно зависит от размера ваших наборов данных. Да, дизайн схемы некорректен, но мы не всегда можем это исправить!

0 голосов
/ 24 апреля 2010

Внешнее соединение ANSI - ваш друг здесь. * = имеет хитрую семантику и ее следует избегать

select distinct a.sign_pk, a.company_pk
from a join b on a.company_pk = b.company_pk 
left outer join c on b.company_location = c.company_location 
                  and (a.sign_pk = c.front_sign or a.sign_pk = c.back_sign) 
where c.company_location is null

Обратите внимание, что предложение , где - это фильтр строк, возвращаемых объединением, поэтому он говорит: "выполнить объединения, но дать мне только те строки, которые не для присоединиться к с "

Внешнее соединение почти всегда быстрее, чем НЕ СУЩЕСТВУЕТ и НЕ В

...