СУЩЕСТВУЕТ и НЕ СУЩЕСТВУЕТ в коррелированном подзапросе

#sql #sql-server #exists #correlated-subquery

#sql #sql-сервер #существует #коррелированный-подзапрос

Вопрос:

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

Учитывая следующие данные;

 DECLARE @Data AS TABLE
(
      OrgId INT,
      ThingId INT
)

DECLARE @ReplacementData AS TABLE
(
      OldThingId INT,
      NewThingId INT
)

INSERT INTO @Data (OrgId, ThingId)
VALUES (1, 2), (1, 3), (1, 4),
       (2, 1), (2, 4),
       (3, 3), (3, 4)

INSERT INTO @ReplacementData (OldThingId, NewThingId)
VALUES (3, 4), (2, 5)
 

Я хочу найти любую организацию, у которой есть «вещь», которая была заменена, как указано в @ReplacementData табличной переменной. Я бы хотел увидеть идентификатор организации, то, что у них есть, которое было заменено, и идентификатор вещи, которая должна его заменить. Так, например, учитывая приведенные выше данные, я должен увидеть;

 Org id, Thing Id, Replacement Thing Id org doesn't have but should have 
1, 2, 5 -- As Org 1 has 2, but not 5
 

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

 -- Attempt using correlated subqueries and EXISTS clauses
-- Show all orgs that have the old thing, but not the new thing
-- Ideally, limit results to OrgId, OldThingId and the NewThingId that they should now have too
SELECT *
  FROM @Data d
 WHERE EXISTS (SELECT *
                 FROM @Data oldstuff
                WHERE oldstuff.OrgId = d.OrgId
                  AND oldstuff.ThingId IN
                (SELECT OldThingID
                   FROM @ReplacementData))
   AND NOT EXISTS (SELECT *
                 FROM @Data oldstuff
                WHERE oldstuff.OrgId = d.OrgId
                  AND oldstuff.ThingId IN
                (SELECT NewThingID
                   FROM @ReplacementData))


   -- Attempt at using a JOIN to only include those old things that the org has (via the where clause)
   -- Also try exists to show missing new things. 
   SELECT *
      FROM @Data d
 LEFT JOIN @ReplacementData rd ON rd.OldThingId = d.ThingId
     WHERE NOT EXISTS (
            SELECT *
              FROM @Data dta
        INNER JOIN @ReplacementData rep ON rep.NewThingId = dta.ThingId
             WHERE dta.OrgId = d.OrgId
    )
   AND rd.OldThingId IS NOT NULL
 

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

Комментарии:

1. Я не на 100% понимаю требования здесь. Можете ли вы уточнить правила? «Я бы хотел увидеть идентификатор организации, то, что у них есть, которое было заменено, и идентификатор вещи, которая должна его заменить», мне непонятен. Я получаю 1,2,5 — но почему не 1,3,4 и 3,3,4???

2. Не 1, 3, 4, потому что в org 1 есть вещи 3 и 4. То же самое с org 3. Он имеет как 3, так и 4. Я хочу найти организации, у которых есть что-то старое, но еще не новое.

3. Понял … ответ идет.

Ответ №1:

Попробуйте это и дайте мне знать.

 DECLARE @Data AS TABLE
(
      OrgId INT,
      ThingId INT
)

DECLARE @ReplacementData AS TABLE
(
      OldThingId INT,
      NewThingId INT
)

INSERT INTO @Data (OrgId, ThingId)
VALUES (1, 2), (1, 3), (1, 4),
       (2, 1), (2, 4),
       (3, 3), (3, 4)

INSERT INTO @ReplacementData (OldThingId, NewThingId)
VALUES (3, 4), (2, 5)

SELECT D.OrgId, RD.*
FROM @Data D 
JOIN @ReplacementData RD
   ON D.ThingId=RD.OldThingId
   LEFT OUTER JOIN @Data EXCLUDE
      ON D.OrgId = EXCLUDE.OrgId
      AND RD.NewThingId = EXCLUDE.ThingId
WHERE EXCLUDE.OrgId IS NULL
 

Комментарии:

1. Это, безусловно, выглядит очень многообещающе. Я попробую это, когда завтра приду на работу, и дам вам знать, как у меня дела. Большое спасибо.

2. Я, наконец, вернулся к тестированию этого, и это работает. Я никогда не склонен использовать самосоединения, и я думаю, что это была недостающая часть головоломки для меня в этом. Я слишком увлекаюсь попытками построить свой запрос вокруг того, как я бы описал проблему (т. Е. Покажите мне все организации, у которых есть старая вещь (существует), но нет новой вещи (не существует)). Ваш метод намного лучше. Еще раз спасибо.