2010-05-17 9 views
3

У меня есть база данных с PermitHolders (PermitNum = PK) и DetailedFacilities каждого держателя разрешения. В таблице tblPermitDetails есть 2 колонкиГруппировка записей по подмножествам SQL

  1. PermitNum (иностранный ключ)
  2. FacilityID (число внешних ключей Поиск в таблице Facility).

У разрешенного лица может быть 1 - 29 предметов на их разрешении, e.i. Разрешение 50 может иметь док-станцию ​​(FacID 4), проложенную дорожку (FacID 17), удерживающую стену (FacID 20) и т. Д. Мне нужен фильтр/дисплей SQL, все, ВСЕ PERMIT #, которые имеют ТОЛЬКО ФАЙЛЫ 19, 20 или 28, не те, у кого есть плюс «х» другие, ... только это подмножество. Я работал над этим в течение 4 дней, кто-нибудь ПОЖАЛУЙСТА, помогите мне? Я отправил в другой BB, но не получил никаких полезных предложений.

Как предложил Одед, вот более подробная информация. Нет таблицы PK для таблицы tblPermitDetails.

Предположим, что у нас есть Permitees 1 - 10; Разрешение 1 - Джон Доу, у него есть док-станция для лодок (FacID 1), Walkway (FacID 4), буй (FacID 7) и Underbrushing (FacID 19) ... это 3 записи для разрешения 1. Разрешение 2 Sus Brown, у нее есть ТОЛЬКО подлесок (FacID 19), Permit 3 - Стив Тони, у него есть док-станция для лодок (FacID 1), Walkway (FacID 4), буй (FacID 7) и Подпорная стена (FacID 20) , Разрешение 4 - Джилл Джек, у нее Подлесок (FacID 19) и Подпорная стена (FacID 20). Я мог бы продолжать, но я надеюсь, что вы последуете за мной. Я хочу, чтобы SQL (для MS Access) показывал мне ТОЛЬКО разрешения 2 & 4 потому что у них есть комбинация FacIDs 19 & 20 [оба или один или другой], НО НЕ ЧТО-НИБУДЬ, например, разрешение 1, у которого есть # 19, но также имеет 4 & 7.

Я надеюсь, что это поможет, пожалуйста, скажите, если нет.

О да, я знаю разницу между i.e и.д. так как я в свои 40 лет написал более 3000 страниц археологических полевых отчетов и магистерской диссертации, но я действительно испытываю стресс здесь от борьбы с этим SQL и не мог меньше заботиться о том, чтобы обратиться к Чикагскому руководству по стилю, прежде чем подавать прошение для помощи. ТАК, DON "T быть застенчивым о моих ошибках композиция! Спасибо!

+0

Вы хотите те, у кого есть только три человека? Или те, кто имеет любую комбинацию из трех лицевых лиц? – Loki

+0

Какой сервер баз данных? MS, Oracle, MySql? – Blorgbeard

+2

@Stacy - ваш вопрос не так-то просто понять, почему он не получает ответы. Можете ли вы отредактировать его и добавить примеры данных и результатов, которые вы хотите? Если мы сможем это увидеть, людям будет намного легче понять, что вам нужно. – Oded

ответ

1

непроверенная, но как о чем-то вроде этого?

SELECT DISTINCT p.PermitNum 
      FROM tblPermitDetails p 
      WHERE EXISTS 
       (SELECT '+' 
        FROM tblFacility f 
        WHERE p.FacilityID = f.FacilityID 
        AND f.facilityID = 19) 
      AND EXISTS 
       (SELECT '+' 
        FROM tblFacility f 
        WHERE p.FacilityID = f.FacilityID 
        AND f.facilityID = 20) 
      AND EXISTS 
       (SELECT '+' 
        FROM tblFacility f 
        WHERE p.FacilityID = f.FacilityID 
        AND f.facilityID = 28) 
      AND NOT EXISTS 
       (SELECT '+' 
        FROM tblFacility f 
        WHERE p.FacilityID = f.FacilityID 
        AND f.facilityID NOT IN (19,20,28)) 
+0

Я думаю, что это делает эту работу. – Garett

+0

Если это делает работу, почему вы не приняли ее как ответ? –

-1

Быстрый способ может быть только смотреть на них ровно три матча (с внутренним запросом), а затем среди тех, которые включают только те, которые имеют 19, 20 и 28.

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

0
SELECT PermitNum 
FROM tblPermitDetails 
WHERE FacilityID IN (19, 20, 28) 
GROUP BY PermitNum 
HAVING COUNT(PermitNum)=3 
+0

Это предполагает, что может быть только одно из объектов, связанных с permitholder – Loki

-1

Хорошо, кажется, я сначала не понял проблему.Так, опять же:

Я воссоздаст пример Стейси здесь:

DECLARE @PermitHolders TABLE 
(PermitNum INT NOT NULL, 
PermitHolder VARCHAR(20)) 

DECLARE @tblPermitDetails TABLE 
(PermitNum INT, 
FacilityID INT) 

INSERT INTO @PermitHolders VALUES (1, 'John Doe') 
INSERT INTO @PermitHolders VALUES (2, 'Sus Brown') 
INSERT INTO @PermitHolders VALUES (3, 'Steve Toni') 
INSERT INTO @PermitHolders VALUES (4, 'Jill Jack') 

INSERT INTO @tblPermitDetails VALUES (1, 1) 
INSERT INTO @tblPermitDetails VALUES (1, 4) 
INSERT INTO @tblPermitDetails VALUES (1, 7) 
INSERT INTO @tblPermitDetails VALUES (1, 19) 
INSERT INTO @tblPermitDetails VALUES (2, 19) 
INSERT INTO @tblPermitDetails VALUES (3, 1) 
INSERT INTO @tblPermitDetails VALUES (3, 4) 
INSERT INTO @tblPermitDetails VALUES (3, 7) 
INSERT INTO @tblPermitDetails VALUES (3, 20) 
INSERT INTO @tblPermitDetails VALUES (4, 19) 
INSERT INTO @tblPermitDetails VALUES (4, 20) 

И это решение:

SELECT * FROM @PermitHolders 
WHERE (PermitNum IN (SELECT PermitNum FROM @tblPermitDetails WHERE FacilityID IN (19, 20, 28))) 
AND (PermitNum NOT IN (SELECT PermitNum FROM @tblPermitDetails WHERE FacilityID NOT IN (19, 20, 28))) 

У меня есть одно наблюдение на стороне: Вы не укажите любой PK для tblPermitDetails. Если не существует, это может быть не очень полезно для производительности. Я рекомендую вам создать PK, используя как PermitNum, так и FacilityID (составной ключ), потому что это будет служить как вашим ПК, так и полезным индексом для ожидаемых запросов.

+0

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

+0

Я тестировал это, и он работает. Пожалуйста, проверьте еще раз. Спасибо – Marwan

0

Я не был уверен, что вы хотите ВСЕ 19,20,28 или ЛЮБОЕ 19,20,28 ... также, это непроверено, но если вы хотите, чтобы какое-либо решение было достаточно близко

Select 
    allowed.PermitNum 
from 
    DetailedFacilties allowed 
    join DetailedFacilities disallowed on allowed.PermitNum != disallowed.PermitNum 
where 
    allowed.FacilityID in (19, 20, 28) 
    and disallowed.FacilityID not in (19, 20, 28) 
0
SELECT DISTINCT PermitNum FROM tblPermitDetails t1 
WHERE FacilityID IN (19, 20, 28) 
    AND NOT EXISTS (SELECT 1 FROM tblPermitDetails t2 
        WHERE t2.PermitNum = t1.PermitNum 
         AND FacilityId NOT IN (19, 20, 28)); 

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

Более оптимизированная версия того же самого запроса будет следующим:

SELECT PermitNum FROM (SELECT DISTINCT PermitNum FROM tblPermitDetails 
         WHERE FacilityID IN (19, 20, 28)) AS t1 
WHERE NOT EXISTS (SELECT 1 FROM tblPermitDetails t2 
        WHERE t2.PermitNum = t1.PermitNum 
         AND FacilityID NOT IN (19, 20, 28)); 

Это немного сложнее читать, но она будет включать в себя меньше «НЕ СУЩЕСТВУЕТ» подзапросы, делая «DISTINCT» часть первой.

Update:

David-W-Fenton упоминает, что НЕ СУЩЕСТВУЕТ следует избегать по причинам оптимизации. За небольшим столом, это, вероятно, не будет иметь значения, много, но вы также можете сделать запрос, используя COUNT (*), если вам необходимо, чтобы избежать НЕ СУЩЕСТВУЕТ:

SELECT DISTINCT PermitNum FROM tblPermitDetails t1 
WHERE (SELECT COUNT(*) FROM tblPermitDetails t2 
     WHERE t1.PermitNum = t2.PermitNum 
      AND FacilityID IN (19, 20, 28)) 
     = 
     (SELECT COUNT(*) FROM tblPermitDetails t3 
     WHERE t1.PermitNum = t3.PermitNum) 
+0

Избегайте НЕ СУЩЕСТВОВАНИЯ в Access - это хорошо, потому что оно неуправляемо оптимизировано и часто не использует индексы с обеих сторон сравнения. –

+0

См. Обновленный ответ. Для маленькой таблицы использование NOT EXISTS, вероятно, не будет иметь заметной разницы, даже если оно сканирует таблицы вместо поиска индекса, но есть другие способы решения проблемы, если это необходимо (хотя у меня есть сомнения, что это будет быстрее, учитывая все подзапросы - это может быть точкой перехода, чтобы придумать что-то более оптимизированное). –

0

насчет (непроверенные)

select permitnum 
from tblPermitDetails t1 
left outer join 
(Select distinct permitnum from tblPermitDetails where facilityId not in (19, 20, or 28)) t2 
on t1.permitnum=t2.permitnum 
where t2.permitnum is null 

т. Е. Мы находим все разрешения, которые не могут соответствовать вашим критериям (у них есть хотя бы одна деталь за пределами тех, которые вы перечисляете), затем мы находим все разрешения, оставшиеся, через левое соединение и критерии.

с правильно настроенными индексами, это должно быть довольно быстро.

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