SQL Server - 在子查询中使用主查询中的列

Posted

技术标签:

【中文标题】SQL Server - 在子查询中使用主查询中的列【英文标题】:SQL Server - use columns from the main query in the subquery 【发布时间】:2012-04-17 12:02:12 【问题描述】:

有没有办法从主查询中实时获取一列,并在子查询中使用它?

类似这样的:(在子查询中使用 A.item)

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

好的,这是真实的:

我需要修改这个现有的查询。以前可以,但是现在数据库改变了,我需要做一些修改,添加一些比较。如您所见,有很多 JOINS,其中一个是子查询。我需要从主查询(例如从表 T0)到子查询(例如: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'' )

【问题讨论】:

您能具体说明“实时获取字段”的含义吗?即时的?这是什么意思? 您不能这样做,因为这不是子查询。这是派生表。根据您的数据库,您可能能够做到这一点。 MS Sql Server 有cross apply / outer apply 用于此目的。更重要的是,你为什么需要它?为什么join不合适? 我为您的实际代码更新了我的答案。您只需向您的JOIN 添加另一个条件即可。 【参考方案1】:

您可以使用 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
                        ) 

【讨论】:

这实际上是正确的答案,适用于无法使用子查询方法或不切实际的情况。【参考方案2】:

您不需要子查询:

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

我想不出这样一种情况,您需要在带有过滤器的子查询上使用JOIN,这不等同于直接在外部查询中引用该字段。

您可以在WHERE 子句的子查询中引用外部表,不过:

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

编辑

对于您的实际代码,只需将JOIN 条件更改为:

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

【讨论】:

嗯,这只是一个例子。真正的查询有点复杂,我真的想要一种像我说的那样的方法,即使我必须使用某种全局变量或任何东西 =/ @JoãoGuilherme 我认为这是一种简化。你到底需要这个做什么? JOIN 这样的场景存在条件。 您可以尝试命名子查询,即 SELECT * FROM a, (SELECT * FROM WHERE a.x=y) b WHERE... 您应该能够做您想做的事。如果嵌套深度超过 3 个,则可能存在限制,这可能是个问题。在网上看可以通过语法 - on (A.x = B.x) @Alex - 如果你是 JOINing 这样的派生表,你必须给它起别名,所以我认为这不会有太大帮助。 遗憾的是没有 db conn 来尝试一些东西,但似乎是你想要的东西:akadia.com/services/sqlsrv_subqueries.html【参考方案3】:

如果您想加入子查询并“实时获取一列”/从主查询中引用一列,那么这样做有一个技巧。

如果将子查询用作别名表,则无法访问子查询之外的表,换句话说,此SQL永远无法访问A:

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

访问A的方式是这样的:

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
)

忽略“前 1”部分,我只是添加了它以表明可能有理由进行这样的连接。 因此,基本上,如果您想在子查询中引用查询中的项目,只需将子查询移动到连接的 ON 部分并使用 IN 关键字,如上图所示。

【讨论】:

这是我需要的。 帮我解决了问题 那是超级昂贵的查询。【参考方案4】:

您可以通过命名主查询和嵌套查询的表来做到这一点。 例如:

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

参考:http://sqlzoo.net/wiki/SELECT_within_SELECT_Tutorial

【讨论】:

ALL关键字msdn.microsoft.com/en-us/library/…的引用【参考方案5】:

不知道为什么人们过于复杂了。 @JNK 是正确的,您可以将谓词移动到主查询中。为了完整起见,我将演示。

您的子查询中有两个谓词引用T0

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

第一个是T6 表上的INNER JOIN 谓词,第二个是WHERE 子句 - 这些都是“硬”过滤器,将过滤掉不匹配的结果(不像@987654326 @ 它将简单地将对该表的值的引用设置为 NULL)。

好吧,既然T6.UnionAll_EmpresaT2.CompanyDb 都需要过滤T0.UnionAll_Empresa,那么我们可以简单地将T6 上的INNER JOIN 谓词更改为:

T2.CompanyDb = T6.UnionAll_Empresa

然后,我们可以去掉子查询中的WHERE子句,我们可以在主查询中将这个JOIN谓词添加到TBI

TBI.CompanyDb = 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 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''
)

这完全等同于您所拥有的,并从您的子查询中删除对 T0 的任何引用。

【讨论】:

【参考方案6】:

你也可以使用WITH

http://msdn.microsoft.com/en-us/library/ms175972.aspx

【讨论】:

不过,这并不能真正回答问题。您将如何使用 CTE 来解决这个问题?

以上是关于SQL Server - 在子查询中使用主查询中的列的主要内容,如果未能解决你的问题,请参考以下文章

如何在子查询 SQL Server 中选择多个项目

如何在 SQL Server 中的 UPDATE 查询的子查询中引用表变量

如何在子查询中使用主查询中的列?

我们如何在子查询 SQL Server 中分配局部变量

SQL 子查询练习

SQL试图在子查询中使用联接表中的列