Как преобразовать sql-запрос с помощью IN, А НЕ IN, UNION с помощью joins

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

Возможно ли преобразовать вложенный запрос с помощью NOT IN, IN и оператора UNION в join? Мне нужен этот запрос с использованием соединений без подзапросов, чтобы spring jpa мог это понять

  SELECT * 
  FROM CONTACT 
  WHERE partner_idpartner = (
     SELECT partner_idpartner 
     FROM BUSINESSCHANNEL WHERE idBusinessChannel in (
       select idbusinessFrom from business WHERE idbusiness = 5943
     )
   )  
   and idcontact not in (
     SELECT CONTACT_IDCONTACT FROM businesscontact 
     WHERE BUSINESS_IDBUSINESS=5943
   )   
  UNION
  SELECT *  
  FROM CONTACT 
  WHERE partner_idpartner = (
    SELECT partner_idpartner 
    FROM BUSINESSCHANNEL WHERE idBusinessChannel in (
      select idbusinessTo FROM business WHERE idbusiness = 5943
    )
  )  
   and idcontact not in (
    SELECT CONTACT_IDCONTACT FROM businesscontact 
    WHERE BUSINESS_IDBUSINESS=5943
  ) 
  

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

1. В каком подзапросе у вас есть два уровня подзапросов?

2. @ Joakim Danielson мне кажется, я не понимаю, о чем вы спрашиваете, вы не видите подзапросы?

3. Да, конечно, но у вас есть подзапросы внутри подзапросов, так что ваш вопрос относится ко всем подзапросам или только к самому внутреннему или …?

4. Да, мы переходим на фреймворк, который не поддерживает вложенные quries, поэтому мне нужно полностью сгладить этот уродливый запрос

5. @Joakim Danielson не один выбирает idbusinessFrom, а второй idbusinessTo

Ответ №1:

Попробуйте это:

 SELECT    DISTINCT CONTACT.*
FROM      CONTACT
JOIN      BUSINESSCHANNEL
ON        CONTACT.partner_idpartner = BUSINESSCHANNEL.partner_idpartner
JOIN      business
ON        (BUSINESSCHANNEL.idBusinessChannel = business.idbusinessFrom
AND       business.idbusiness = 5943)
OR        (BUSINESSCHANNEL.idBusinessChannel = business.idbusinessTo)
AND       business.idbusinessroute = 5943)
LEFT JOIN businesscontact
ON        CONTACT.idcontact = businesscontact.CONTACT_IDCONTACT 
AND       BUSINESS_IDBUSINESS = 5943
WHERE     businesscontact.CONTACT_IDCONTACT IS NULL
  

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

1. Хотя я думаю, что этот запрос может дать вам результаты, его количество элементов может быть неправильным. Возможно, могло бы помочь добавление DISTINCT предложения в main select.

2. Даже не думал об этом, теперь мой запрос кажется уродливым :/

Ответ №2:

Вы можете преобразовать все эти подзапросы в объединения. Недостатком является то, что вы теряете читаемость и можете получить огромный промежуточный результат, от которого затем придется избавиться DISTINCT . Это может быть довольно дорогостоящим. NOT IN может быть преобразован в антисоединение (внешнее объединение с последующим выбором несовпадающих строк), что является еще одним шаблоном, который может привести к нежелательно большому промежуточному результату.

 SELECT DISTINCT c.*  
FROM contact c
JOIN businesschannel bc ON bc.partner_idpartner = c.partner_idpartner
JOIN business b ON bc.idbusinesschannel IN (b.idbusinessfrom, b.idbusinessto)
                AND b.idbusiness = 5943 
LEFT JOIN businesscontact bco ON bco.contact_idcontact = c.idcontact
                              AND bco.business_idbusiness = 5943
WHERE bco.contact_idcontact IS NULL;
  

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

1. Да, я полностью согласен. Теоретически можно удалить подзапросы, но я думаю, что это непрактично. Производительность результирующего запроса может быть катастрофической. Даже если у вас лучшие индексы, запрос может быть очень медленным.

Ответ №3:

Попробуйте этот запрос: я не тестировал

 DECLARE @tblNotInIUdContact TABLE (  CONTACT_IDCONTACT INT)
DECLARE @tblIdBusinessFrom TABLE (   IdBusiness INT)
DECLARE @tblIdBusinessTo TABLE (     IdBusiness INT)
DECLARE @tblIdPartner TABLE (    partner_idpartner INT)

INSERT INTO @tblNotInIUdContact(CONTACT_IDCONTACT)
SELECT CONTACT_IDCONTACT FROM businesscontact WHERE BUSINESS_IDBUSINESS=5943

INSERT INTO @tblIdBusinessFrom(IdBusiness)
select idbusinessFrom from business  WHERE idbusiness=5943

INSERT INTO @tblIdBusinessTo(IdBusiness)
select idbusinessTo FROM business    WHERE idbusinessroute=5943

INSERT INTO @tblIdPartner(partner_idpartner)
SELECT partner_idpartner FROM BUSINESSCHANNEL bc
INNER JOIN @tblIdBusinessFrom bf ON bc.partner_idpartner = bf.IdBusiness

INSERT INTO @tblIdPartner(partner_idpartner)
SELECT partner_idpartner FROM BUSINESSCHANNEL bc
INNER JOIN @tblIdBusinessTo bf ON bc.partner_idpartner = bf.IdBusiness



SELECT * FROM CONTACT c
    INNER JOIN @tblIdPartner p ON c.partner_idpartner = p.partner_idpartner  
EXCEPT
SELECT * FROM CONTACT c
    INNER JOIN @tblNotInIUdContact ic ON c.idcontact = ic.CONTACT_IDCONTACT
  

Ответ №4:

Здесь вы переходите

  1. чтобы заменить, где in: используйте inner join
  2. чтобы заменить там, где не in: используйте левое внешнее соединение tab2, где tab2.col равно нулю
  3. чтобы заменить объединение, я создаю временную таблицу #mycontact с той же структурой, что и CONTACT

    выберите * в mycontact из contact, где 1= 0

    вставить в #mycontact SELECT * ИЗ CONTACT TA

    внутреннее соединение (ВЫБЕРИТЕ partner_idpartner ИЗ BUSINESSCHANNEL T0 внутреннее соединение (выберите idbusinessFrom из business, ГДЕ idbusiness=5943) T1 на T0.idBusinessChannel=T1.idbusinessFrom) левое внешнее соединение (ВЫБЕРИТЕ CONTACT_IDCONTACT ИЗ businesscontact, ГДЕ BUSINESS_IDBUSINESS=5943) T2 на T0.idcontact=T2.CONTACT_IDCONTACT, где T2. CONTACT_IDКОНТАКТ равен нулю) TB на TA.partner_idpartner=TB.partner_idpartner

    вставить в #mycontact

    ВЫБЕРИТЕ *
    ИЗ CONTACT TC inner join(Внутреннее объединение)

     (SELECT partner_idpartner FROM BUSINESSCHANNEL  T0
    INNER JOIN (  select idbusinessTo FROM business     WHERE idbusinessroute=5943) T1 on T0.idBusinessChannel=T1.idbusinessFrom)  
    
    left outer join ( SELECT CONTACT_IDCONTACT FROM businesscontact WHERE BUSINESS_IDBUSINESS=5943)  T2
    on T0.idcontact=T2.CONTACT_IDCONTACT
      

    где T2.CONTACT_IDCONTACT равно нулю)

     TD on TC.partner_idpartner=TD.partner_idpartner
      

    выберите * из #mycontact