SQL-запрос - необходимо исключить, если требование НЕ выполнено, и исключить, если выполнено условие дисквалификации - PullRequest
1 голос
/ 12 февраля 2012

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

У меня есть справочная таблица, скажем TableB, которая выглядит следующим образом. Все поля INT, кроме двух последних, которые являются BOOL.

ID, TableA_ID, Value, Required, Disqualifies

У меня есть список TableA_Id значений (1, 2, 3 ) и т. Д.

Для каждой записи в этой таблице либо Обязательное может быть истинным, либо дисквалификация может быть истинной - обе они не могут быть истинными одновременно. Они оба могут быть ложными или нулевыми. Могут быть повторяющиеся значения TableA_Id, но никогда не должно быть дубликатов TableA_Id и Value

Если значение true для любого из этих значений TableA_ID, и ни одно из этих значений не находится в моем списке, не возвращает записей. Если ни одно из значений не помечено как обязательное (required = 0 or null), то возвращаются записи UNLESS , любое из значений помечается как дисквалифицирующее и находится в списке, и в этом случае я хочу вернуть никаких записей.

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

Надеюсь, я все объяснил ясно.

Заранее спасибо за указание в правильном направлении.

В качестве примера того, как могут выглядеть мои записи:

ID  TableA_ID  Value  Required  Disqualifies
--  ---------  -----  --------  ------------
1   123        1      True      False
2   123        2      True      False
3   123        3      False     False
4   123        4      False     True
5   456        1      False     True
6   456        2      False     False

Учитывая этот набор примеров данных, если мы работаем с TableA_Id 123 и мой список значений, скажем, 1 и 3, я получу возвращенные данные, потому что у меня есть обязательное значение и нет никаких дисквалифицированных значений. Если бы мой список значений был только 3, я не получил бы никаких записей, так как я пропускаю Обязательные значения. Если бы мой список значений был 1 и 4, я бы не получил записей, потому что 4 помечен как дисквалифицированный.

Теперь, если мы работаем с TableA_Id 456, единственный список значений, который будет возвращать любые записи, равен 2.

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

Вот полный динамически сгенерированный запрос. Сейчас я работаю над второй строкой снизу. Чтобы сравнить это с моим примером, t.id будет TableA_ID, Value будет PDT_ID.

SELECT DISTINCT t.ID, t.BriefTitle, stat.Status, lstat.Status AS LocationStatus, st.SType, t.LAgency, l.City, state.StateCode
,( SELECT TOP 1 UserID  
FROM TRecruiter 
WHERE TrialID = t.ID AND Lead = 1 ), l.ID as LocationID
, l.WebBased 
FROM Trial t 
INNER JOIN Location l ON t.ID = l.TrialID       
FULL JOIN pdt on t.ID = pdt.trialid       
FULL JOIN pdm on t.ID = pdm.TrialID       
FULL JOIN s on t.ID = s.TrialID       
FULL JOIN hy on t.ID = hy.TrialID       
FULL JOIN ta on t.ID = ta.TrialID       
FULL JOIN stt on t.ID = stt.TrialID       
FULL JOIN [Status] stat ON t.StatusID = stat.ID       
FULL JOIN st ON t.StudyTypeID = st.ID       
FULL JOIN State state ON l.StateID = state.ID       
FULL JOIN [Status] lstat ON l.StatusID = lstat.ID       
FULL JOIN ts ON t.ID = ts.TrialID       
FULL JOIN tpdm ON t.ID = tpdm.TrialID      
WHERE ((t.ID IS NOT NULL) 
AND (EligibleHealthyVolunteers IS NULL OR EligibleHealthyVolunteers = 1 OR (0 = 0 AND EligibleHealthyVolunteers = 0)) 
AND (eligiblegenderid is null OR eligiblegenderid = 1 OR eligiblegenderid = 3) 
AND ((EligibleMinAge <= 28 AND EligibleMaxAge >= 28) OR (EligibleMinAge <= 28 AND EligibleMaxAge is null) OR (EligibleMinAge IS NULL AND EligibleMaxAge >= 28)) 
AND (HYID = 6 AND (hy.Disqualify = 0 OR hy.Disqualify IS NULL AND NOT EXISTS (SELECT * FROM hy WHERE t.id = hy.TrialID AND hy.Req =1)) OR HYID = 6 AND hy.req = 1)
AND (PDT_ID IN (1) AND ( pdt.Disqualify = 0 OR pdt.Disqualify IS NULL AND NOT EXISTS (select * from pdt where t.id = pdt.TrialID AND pdt.Req = 1)) OR PDT_ID IN (1) AND (pdt.Req = 1 AND (pdt.Disqualify = 0 or pdt.Disqualify is null )))      
) AND ((3959 * acos(cos(radians(34.18)) * cos(radians(l.Latitude)) * cos(radians(l.Longitude) - radians(-118.46)) + sin(radians(34.18)) * sin(radians(l.Latitude)))) <= 300 OR l.Latitude IS NULL) AND t.IsPublished = 1 AND (t.StatusID = 1 OR t.StatusID = 2) 

Я изменил / сократил некоторые имена таблиц только из соображений безопасности / конфиденциальности.

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

У меня есть следующий бит sql:

AND ( exists (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id AND pdT_ID IN (2) )  AND EXISTS (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id    )     )

Я не уверен, как это структурировать. Эти два существующих утверждения должны сделать все это правдой в следующей комбинации: Верно и Неверно Правда правда Ложь и ложь

Если это Ложь и Правда, тогда все это ложно. Другими словами, если существует Req = 1 И PDT_ID, помеченный как Req = 1, отсутствует в нашем списке (в приведенном выше примере список содержит только «2»), тогда верните false.

EDIT: Я думаю, что я наконец получил это.

AND NOT EXISTS (SELECT * FROM  pdt WHERE Disqualify = 1 AND trialid = t.id AND  PDT_ID IN (2)  )
AND NOT ( NOT exists (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id AND PDT_ID IN (2) )  AND EXISTS (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id    )  )

Пока что это похоже на тестирование. Хотя я работаю только с двумя значениями PDT_ID. Если это решит мою проблему, я вернусь и дам кому-нибудь кредит за помощь.

Ответы [ 3 ]

0 голосов
/ 12 февраля 2012
SELECT * 
FROM TABLEB B
WHERE 
(
   B.REQUIRED = 1 
   AND EXISTS
   (
     SELECT 1
     FROM TABLEA A
     WHERE A.ID =B.TABLEA_ID
   )
)
OR
(
  B.REQUIRED != 1
  AND B.DISQUALIFIES <> 1

)
OR
(
    B.REQUIRED != 1
    AND B.DISQUALIFIES = 1
    AND EXISTS
    (
     SELECT 1
     FROM TABLEA A
     WHERE A.ID =B.TABLEA_ID
    ) 

)
0 голосов
/ 13 февраля 2012

(Похоже, вы нашли решение, но я все равно решил поделиться своими мыслями об этой проблеме.)

Учитывая, что у вас есть набор TableAИдентификаторы, каждый из которых сопровождается набором некоторых значений, и вы хотите протестировать весь набор строк с этим TableB, используя правила, которые вы изложили, я думаю, что весь процесс проверки может выглядеть следующим образом:

  1. Сопоставьте каждую пару TableA.ID и Value с TableB и получите совокупные максимумы Required и Disqualifies для каждого TableA.ID на этом пути.

  2. Вывести отдельный список значений TableA_ID с соответствующими им максимальными значениями Required из TableB.Нам будет необходимо знать, должно ли конкретное TableA_ID иметь требуемое значение вообще.

  3. Сопоставить набор строк, полученный на этапе 1, с производнымтаблица (Этап 2) и проверьте значения агрегирования:

    1) если фактический агрегат Disqualifies для TableA_ID равен 1, отбросьте этот набор TableA_ID;

    2) если TableA_ID имеет совпадение в производной таблице 2-го этапа, а совокупный максимум Required, полученный нами на этапе 1, не совпадает с максимальным Required в производной таблице, также отбрасывать набор.

Что-то подсказывает мне, что в этот момент было бы лучше перейти к некоторой иллюстрации.Вот пример сценария с комментариями, объясняющими, какая часть сценария реализует какую часть описания выше:

;
WITH

/* this is the row set to be tested and which
   is supposed to contain TableA.IDs and Values */
testedRowSet AS (
  SELECT
    TableA.ID AS TableA_ID,
    SomethingElse.TestedValue AS Value,
    ...
  FROM TableA
    JOIN SomethingElse ON <i>some_condition</i>
    ...
),

/* at this point, we are getting the aggregate maximums
   of TableB.Required and TableB.Disqualifies for every
   TableA_ID in testedRowSet */
aggregated AS (
  SELECT
    testedRowSet.TableA_ID,
    testedRowSet.Value,
    ...
    DoesHaveRequiredValues = MAX(CASE TableB.Required     WHEN 1 THEN 1 ELSE 0 END) OVER (PARTITION BY testedRowSet.TableA_ID),
    HasDisqualifyingValues = MAX(CASE TableB.Disqualifies WHEN 1 THEN 1 ELSE 0 END) OVER (PARTITION BY testedRowSet.TableA_ID)
  FROM testedRowSet
    LEFT JOIN TableB ON testedRowSet.TableA_ID = TableB.TableA_ID
                    AND testedRowSet.Value     = TableB.Value
),

/* this row set will let us see whether a particular
   TableA_ID must have a required value */
properties AS (
  SELECT
    TableA_ID,
    MustHaveRequiredValues = MAX(CASE Required WHEN 1 THEN 1 ELSE 0 END)
  FROM TableB
  GROUP BY TableA_ID
),

/* this is where we are actually checking the previously
   obtained aggregate values of Required and Disqualifies */
tested AS (
  SELECT
    aggregated.TableA_ID,
    aggregated.Value,
    ...
  FROM aggregated
    LEFT JOIN properties ON aggregated.TableA_ID = properties.TableA_ID
  WHERE aggregated.HasDisqualifyingValues = 0
    AND (properties.TableA_ID IS NULL
      OR properties.MustHaveRequiredValues = aggregated.DoesHaveRequiredValues)
)

SELECT * FROM tested
0 голосов
/ 12 февраля 2012

ОБНОВЛЕНИЕ - после РЕДАКТИРОВАНИЯ и объяснения от ОП:

Измените строку

FULL JOIN pdt on t.ID = pdt.trialid

На

FULL JOIN (SELECT * FROM pdt BB WHERE
BB.TrialID IN (SELECT AA.ID FROM Trial AA WHERE AA.ID = BB.TrialID) AND
1 > (SELECT COUNT(*) FROM Trial A
LEFT OUTER JOIN pdt B ON B.Req != 1 AND B.Disqualify != 1 AND B.TrialID = A.ID
WHERE B.TrialID IS NULL)) pdt ON t.ID = pdt.TiralID

И изменитестрока перед последним от

AND (PDT_ID IN (1) AND ( pdt.Disqualify = 0 OR pdt.Disqualify IS NULL AND NOT EXISTS (select * from pdt where t.id = pdt.TrialID AND pdt.Req = 1)) OR PDT_ID IN (1) AND (pdt.Req = 1 AND (pdt.Disqualify = 0 or pdt.Disqualify is null ))) 

до

AND PDT_ID IN (1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...