Est-il possible de convertir une sous-requête avec les opérateurs NOT IN, IN et UNION pour la rejoindre? J'ai besoin de cette requête en utilisant des jointures sans sous-requêtes pour que spring jpa puisse comprendre que
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
)
4 Réponses :
Essayez cette requête: je n'ai pas testé
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
Essayez ceci:
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
Bien que je pense que cette requête pourrait vous donner les résultats, sa cardinalité peut être incorrecte. Peut-être que l'ajout d'une clause DISTINCT sur la sélection principale pourrait aider.
Je n'ai même pas pensé à cela, maintenant ma requête est laide: /
Vous pouvez convertir toutes ces sous-requêtes en jointures. L'inconvénient est que vous perdez la lisibilité et peut produire un énorme résultat intermédiaire dont vous devez alors vous débarrasser avec DISTINCT . Cela peut être assez coûteux. NOT IN peut être converti en une anti-jointure (jointure externe, puis sélection des lignes non correspondantes), qui est un autre modèle qui peut produire un résultat intermédiaire trop volumineux.
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;
Oui, je suis totalement d'accord. La suppression des sous-requêtes peut théoriquement être effectuée, mais je pense que ce n'est pas pratique. Les performances de la requête résultante peuvent être catastrophiques. Même si vous disposez des meilleurs index, la requête peut être très lente.
Ici, allez
pour remplacer union, Je crée une table temporaire #mycontact avec la même structure que CONTACTER
sélectionnez * dans mon contact à partir du contact où 1 = 0
insérer dans #mycontact CHOISIR * DE CONTACT TA
jointure interne (SELECT partner_idpartner FROM BUSINESSCHANNEL T0 jointure interne (sélectionnez idbusinessFrom de business WHERE idbusiness = 5943) T1 sur T0.idBusinessChannel = T1.idbusinessFrom) jointure externe gauche (SELECT CONTACT_IDCONTACT FROM businesscontact WHERE BUSINESS_IDBUSINESS = 5943) T2 sur T0.idcontact = T2.CONTACT_IDCONTACT où T2.CONTACT_IDCONTACT est nul) TB sur TA.partner_idpartner = TB.partner_idpartner
insérer dans #mycontact
SELECT *
DE CONTACT TC
jointure interne (
TD on TC.partner_idpartner=TD.partner_idpartner
où T2.CONTACT_IDCONTACT est nul)
(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
sélectionnez * dans #mycontact
Quelle sous-requête, vous avez deux niveaux de sous-requêtes?
@ Joakim Danielson je ne pense pas que je comprends ce que vous demandez, vous ne voyez pas de sous-requêtes?
Oui, bien sûr, mais vous avez des sous-requêtes dans les sous-requêtes, votre question se réfère-t-elle à toutes les sous-requêtes ou seulement aux plus profondes ou ...?
Oui, nous migrons vers un framework qui ne prend pas en charge les sous-requêtes, je dois donc aplatir complètement cette vilaine requête
Votre «nouveau framework» prend-il en charge les CTE (Common Table Expressions)?
@The Impaler oui, mais j'évite de l'utiliser, car je dois prendre en charge plusieurs sources de données
@Joakim Danielson il n'y a pas un seul sélectionne idbusinessDe et deuxième idbusinessTo
Je pense que c'est une bonne question dont la réponse est probablement "ne le faites pas". Je vais voter pour la question car elle est utile à d'autres personnes.
Sur une note latérale:
WHERE partner_idpartner = (...)me semble douteux, car la sous-requête semble renvoyer plusieurs lignes, donc elle devrait plutôt êtreWHERE partner_idpartner IN (...). La requête entière pourrait facilement être simplifiée en passant en utilisantEXISTSafin de rechercheridbusinessFrometidbusinessFromen une seule étape. Nous pourrions ainsi nous débarrasser de la moitié de la requête et elle s'exécuterait probablement plus rapidement aussi.