web-dev-qa-db-fra.com

SQL Server - utilisez les colonnes de la requête principale dans la sous-requête

Existe-t-il un moyen d'obtenir une colonne en temps réel, à partir d'une requête principale, et de l'utiliser dans une sous-requête?

Quelque chose comme ceci: (Utilisez A.item dans la sous-requête)

SELECT item1, * 
FROM TableA A 
INNER JOIN 
(
    select * 
    from TableB B 
    where A.item = B.item
) on A.x = B.x;

Ok, voici la vraie chose:

J'ai besoin de modifier cette requête existante. Cela fonctionnait auparavant, mais maintenant que la base de données a changé, je dois faire quelques modifications, ajouter des comparaisons. Comme vous pouvez le voir, il y a beaucoup de JOINS, et l'un d'eux est une sous-requête. Je dois ajouter une comparaison d'une colonne de la requête principale (de la table T0 par exemple) à la sous-requête (comme ceci: T6.UnionAll_Empresa = T0.UnionALl_Empresa)

Select T0.UnionAll_Empresa,<STUFF>

from [UNION_ALL_BASES]..OINV T0 with (nolock)
inner join [UNION_ALL_BASES]..INV6 T1 with (nolock) on t0.DocEntry = t1.DocEntry and t0.UnionAll_Empresa = t1.UnionAll_Empresa
inner join

(
select 
t1.CompanyID,
T2.CompanyDb,
t1.OurNumber,
T6.BankCode,
T6.BankName,
T3.[Description] Situation,
T1.[Status],
T5.Descrption nomeStatus,
T1.Origin,
T1.DocEntry,
T1.DocType,
T1.ControlKey,
T1.CardCode,
T4.[Description] ContractBank,
T1.PayMethodCode,
T1.DueDate,
T1.DocDate,
T1.InstallmentID,
T1.InstallmentValue,
T1.Correction,
T1.InterestContractural,
T1.FineContract,
T1.ValueAbatment,
T1.ValueDiscount,
T1.ValueFineLate,
T1.ValueInterestDaysOfLate,
T1.OtherIncreases,
T1.ValueInWords,
T1.ValueDocument,
T1.DigitalLine,
T1.Document
from [IntegrationBank]..BillOfExchange T1 with (nolock)
    inner join [InterCompany2]..CompanyHierarchy T2 with (nolock) on T1.CompanyID = T2.ID
    left join [IntegrationBank]..BillOfExchangeSituation T3 with (nolock) on T1.Situation = T3.ID 
    inner join [IntegrationBank]..ContractBank T4 with (nolock) on T1.ContractBank = T4.ID 
    inner join [IntegrationBank]..BoeStatus T5 with (nolock) on T1.[Status] = T5.ID 
    inner join [UNION_ALL_BASES]..ODSC T6 with (nolock) on T4.BankKey = T6.AbsEntry and **T6.UnionAll_Empresa = T0.UnionALl_Empresa** --I need to do this 
where T1.[Status] <> 5 
and T2.CompanyDb = **T0.UnionAll_Empresa** --I need to do this
) TBI on (T1.DocEntry = TBI.DocEntry and T1.InstlmntID = TBI.InstallmentID and TBI.DocType = T1.ObjType )
inner join [UNION_ALL_BASES]..OCTG T2 on T0.GroupNum = T2.GroupNum and T0.UnionAll_Empresa = T2.UnionAll_Empresa
inner join [UNION_ALL_BASES]..OSLP T3 on T0.SlpCode = T3.SlpCode and T0.UnionAll_Empresa = T3.UnionAll_Empresa
where not exists (select 1
        from [UNION_ALL_BASES]..RIN1 A with (nolock) 
                inner join [UNION_ALL_BASES]..ORIN B with (nolock) on A.DocEntry = B.DocEntry and A.UnionAll_Empresa = B.UnionAll_Empresa
        where A.BaseEntry = T0.DocEntry
        and   B.SeqCode = ''1'' )
37
João Guilherme

Vous pouvez utiliser OUTER APPLY

   SELECT  *
    FROM    tbl1
            OUTER APPLY ( SELECT TOP 1
                                    currency_id,
                                    SUM(taxrate) AS taxrate
                          FROM      tbl2
                          WHERE     wuptr.currency_id = tbl1.currency_id
                          GROUP BY  tbl2.currencyid
                        ) 
39
mmmmmm

Vous n'avez pas besoin d'une sous-requête pour cela:

SELECT item1, * 
FROM TableA A 
INNER JOIN 
   TableB B 
     ON A.item = B.item
     AND A.x = B.x;

Je ne peux pas penser à un scénario où vous auriez besoin de JOIN sur une sous-requête avec un filtre comme celui où il ne serait pas équivalent de simplement référencer le champ directement dans la requête externe.

Vous pouvez cependant référencer la table externe dans la sous-requête dans la clause WHERE:

SELECT <stuff>
FROM Table t
WHERE EXISTS  (SELECT 1 from TableB B 
               WHERE t.id = b.id)

MODIFIER

Pour votre code réel, changez simplement les critères JOIN en ceci:

) TBI on (T1.DocEntry = TBI.DocEntry
          and T1.InstlmntID = TBI.InstallmentID 
          and TBI.DocType = T1.ObjType
          AND TBI.CompanyDB = T0.UnionAll_Empresa )
20
JNK

Si vous souhaitez vous associer à une sous-requête et "obtenir une colonne en temps réel"/référencer une colonne de la requête principale, il y a une astuce pour le faire.

Vous ne pouvez pas accéder aux tables qui sont en dehors de la sous-requête si elle est utilisée comme table aliasée, en d'autres termes, ce SQL ne peut jamais accéder à A:

...
INNER JOIN 
(
    select * 
    from TableB B 
    where A.item = B.item
) on A.x = B.x;

La façon d'accéder à A serait la suivante:

SELECT item1, * 
FROM TableA A 
INNER JOIN TableB on TableB.item = TableA.item and TableB.item in
(
    select top 1 B.Item
    from TableB B 
    where A.item = B.item
)

Ignorez simplement la pièce "top 1", je viens d'ajouter cela pour montrer qu'il peut y avoir une raison pour faire une jointure comme celle-ci.
Donc, fondamentalement, si vous souhaitez référencer un élément de la requête dans la sous-requête, déplacez simplement la sous-requête vers la section ON d'une jointure et utilisez le mot clé IN comme illustré ci-dessus.

12
Stephen Smuts

Vous pouvez le faire en nommant les tables de la requête principale et de la requête imbriquée. Par exemple:

SELECT continent, name, population FROM world x
  WHERE population >= ALL
    (SELECT population FROM world y
        WHERE y.continent=x.continent
          AND population>0)

référence: http://sqlzoo.net/wiki/SELECT_within_SELECT_Tutorial

9
Mohamed Nagieb

Je ne sais pas pourquoi les gens compliquent trop cela. @JNK a raison de pouvoir déplacer le prédicat dans la requête principale. Pour être complet, je vais démontrer.

Votre sous-requête contient deux prédicats qui font référence à T0:

T6.UnionAll_Empresa = T0.UnionAll_Empresa
T2.CompanyDb = T0.UnionAll_Empresa

Le premier est un INNER JOIN prédicat sur la table T6, et la seconde une clause WHERE - ce sont tous les deux des filtres "durs" et filtreront les résultats qui ne correspondent pas (contrairement à un LEFT OUTER JOIN qui mettra simplement la référence aux valeurs de cette table à NULL).

Eh bien, puisque T6.UnionAll_Empresa et T2.CompanyDb les deux doivent filtrer contre T0.UnionAll_Empresa, alors nous pouvons simplement changer le INNER JOIN prédicat sur T6 pour ça:

T2.CompanyDb = T6.UnionAll_Empresa

Ensuite, nous pouvons supprimer la clause WHERE dans la sous-requête, et nous pouvons ajouter ce prédicat JOIN à TBI dans la requête principale:

TBI.CompanyDb = T0.UnionAll_Empresa

... ce qui rend la requête entière ceci:

Select T0.UnionAll_Empresa,<STUFF>

from [UNION_ALL_BASES]..OINV T0 with (nolock)
inner join [UNION_ALL_BASES]..INV6 T1 with (nolock) on t0.DocEntry = t1.DocEntry and t0.UnionAll_Empresa = t1.UnionAll_Empresa
inner join
(
    select 
    t1.CompanyID,
    T2.CompanyDb,
    t1.OurNumber,
    T6.BankCode,
    T6.BankName,
    T3.[Description] Situation,
    T1.[Status],
    T5.Descrption nomeStatus,
    T1.Origin,
    T1.DocEntry,
    T1.DocType,
    T1.ControlKey,
    T1.CardCode,
    T4.[Description] ContractBank,
    T1.PayMethodCode,
    T1.DueDate,
    T1.DocDate,
    T1.InstallmentID,
    T1.InstallmentValue,
    T1.Correction,
    T1.InterestContractural,
    T1.FineContract,
    T1.ValueAbatment,
    T1.ValueDiscount,
    T1.ValueFineLate,
    T1.ValueInterestDaysOfLate,
    T1.OtherIncreases,
    T1.ValueInWords,
    T1.ValueDocument,
    T1.DigitalLine,
    T1.Document
    from [IntegrationBank]..BillOfExchange T1 with (nolock)
    inner join [InterCompany2]..CompanyHierarchy T2 with (nolock) on T1.CompanyID = T2.ID
    left join [IntegrationBank]..BillOfExchangeSituation T3 with (nolock) on T1.Situation = T3.ID 
    inner join [IntegrationBank]..ContractBank T4 with (nolock) on T1.ContractBank = T4.ID 
    inner join [IntegrationBank]..BoeStatus T5 with (nolock) on T1.[Status] = T5.ID 
    inner join [UNION_ALL_BASES]..ODSC T6 with (nolock) on T4.BankKey = T6.AbsEntry and T2.CompanyDb = T6.UnionAll_Empresa
    where T1.[Status] <> 5 
) TBI on (T1.DocEntry = TBI.DocEntry and T1.InstlmntID = TBI.InstallmentID and TBI.DocType = T1.ObjType and TBI.CompanyDb = T0.UnionAll_Empresa)
inner join [UNION_ALL_BASES]..OCTG T2 on T0.GroupNum = T2.GroupNum and T0.UnionAll_Empresa = T2.UnionAll_Empresa
inner join [UNION_ALL_BASES]..OSLP T3 on T0.SlpCode = T3.SlpCode and T0.UnionAll_Empresa = T3.UnionAll_Empresa
where not exists (
    select 1
    from [UNION_ALL_BASES]..RIN1 A with (nolock) 
    inner join [UNION_ALL_BASES]..ORIN B with (nolock) on A.DocEntry = B.DocEntry and A.UnionAll_Empresa = B.UnionAll_Empresa
    where A.BaseEntry = T0.DocEntry
    and B.SeqCode = ''1''
)

Ceci est entièrement équivalent à ce que vous avez et supprime toute référence à T0 de votre sous-requête.

1
e_i_pi