#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:
Здесь вы переходите
- чтобы заменить, где in: используйте inner join
- чтобы заменить там, где не in: используйте левое внешнее соединение tab2, где tab2.col равно нулю
-
чтобы заменить объединение, я создаю временную таблицу #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