【问题标题】:Using multiple and interdepended CROSS-APPLY across multiple tables在多个表中使用多个相互依赖的 CROSS-APPLY
【发布时间】:2021-06-06 19:08:30
【问题描述】:

如何使用CROSS APPLY(或INNER JOIN)根据其他表中的值从一个表中获取数据?

即我有以下表格:

表格说明:

ProdID Description TrackNum
361 Test 1 499
388 Test 2 003
004 5599
238 Test 3 499
361 Test 10 555
004 Test 40 555

餐桌产品:

ProdID ProductName Price
361 P1 5.00
388 P2 5.00
004 P3 12.00
238 P4 6.00
515 P5 7.00
636 P6 7.00
775 P7 7.00
858 P8 8.00

表格发票:

ProdID TrackNum InvoiceID
361 499 718
388 199 718
004 499 718
238 499 718
361 555 333
004 555 444
361 111 444
388 222 333
616 116 565
717 116 565
361 003 221
388 003 221
004 5599 728

我需要我的查询做的是:

  1. 先进入 Invoices 表,只获取与指定 InvoiceID 和 TrackNum 匹配的记录;
  2. 然后进入 Products 表并获取 only 行在 ProdID 我在第 1 步中提取的数据与数据存在于 Products 表中。
  3. 然后最终从 Descriptions 表中获取所有列,但仅针对我在第 2 步中获得且与 ProdID 匹配的行。

我最后需要的是这样的(如果我得到更多的列,那很好,但我不想得到更多的行):

ProdID Description TrackNum
361 Test 1 499
004 5599
238 Test 3 499

我有以下查询(我曾尝试使用 INNER JOINCROSS APPLY) - 但它返回的行数超出了我的需要:

SELECT * FROM [Descriptions] AS [DES] 
CROSS APPLY
(
    select * from [Invoices] AS [INV] where [INV].[TrackNum] = '499' AND [INV].[InvoiceID] = '718'
) [INV]
CROSS APPLY 
    (
        select * from [Products] AS [GP] 
        WHERE [GP].[ProdID] = [INV].[ProdID]
    ) [GP2]
WHERE 
[DES].[ProdID] = [GP2].[ProdID]
order by [DES].[ProdID] asc

【问题讨论】:

  • 您在任何地方都没有条件,说明哪个描述记录与哪个发票记录相关联。因此,您将找到的所有发票应用于每一个描述。
  • 这可能会有所帮助...stackoverflow.com/questions/1139160/…
  • 看起来您可以使用where exists 代替加入或交叉应用

标签: sql sql-server performance inner-join cross-apply


【解决方案1】:
SELECT
  *
FROM
  invoices   AS i
LEFT JOIN
  descriptions   AS d
    ON  d.prodid = i.prodid
    AND d.tracknum = i.tracknum -- you don't have this, but I think it's required.
LEFT JOIN
  products   AS p
    ON  p.prodid = i.prodid
WHERE
      i.invoiceid = 718
  AND i.tracknum = 499
ORDER BY
  i.prodid

我担心的一件事是发票和说明都有一个名为 tracknum 的列,但您的查询和预期数据表明您不想将其包含在联接中?这非常令人困惑,要么是一个糟糕的列名,要么是您的查询和示例结果中的错误。

【讨论】:

  • @DaleK 感谢您的编辑,但我用大写字母来强调“不要”这个词;)改为粗体......(尽管可以更正错别字,我是在手机上这样做的,所以它很容易闻到 pistake 的味道。)
  • 这就是差错,我需要没有描述的 ProdID = 004(即使它是 TrackNum = 5599)在我的最终输出中。但是如果我使用 AND d.tracknum = i.tracknum - 那么这一行将不会在最后,如果我不使用它 - 它会返回太多行:(
  • 谢谢各位!我错过了左边的部分。这就是我需要的!
【解决方案2】:

根据您的描述,您需要以下内容,从您的 Invoices 表和 where 子句开始获取正确的行,然后加入 ProductsDescriptions

我也猜你想匹配Description 上的TrackNum?因为看起来你每个ProdId/TrackNum 组合都有一个独特的Description

select [INV].[ProdID], [DES].[Description], [INV].[TrackNum]
from [Invoices] as [INV]
inner join [Products] as [GP] on [GP].[ProdID] = [INV].[ProdID]
inner join [Descriptions] on [DES].[ProdID] = [GP].[ProdID] and [DES].[TrackNum] = [INV].[TrackNum]
where [INV].[TrackNum] = '499' AND [INV].[InvoiceID] = '718'
order by [DES].[ProdID] asc;

注意:您通常只对要在主表中的每行运行/评估某些内容的查询使用“CROSS APPLY”。

【讨论】:

  • 可能想成为select distinct [INV].[ProdID], [DES].[Description], [INV].[TrackNum],以确保连接中没有重复
  • @David784 我不喜欢独特的,IMO 使用distinct 意味着没有正确设计查询。如果可能有重复的产品,我会分组。但会等着看 OP 说什么。
  • 可能需要 LEFT JOIN,因为发票的 tracknum 为 499,但一个描述的 tracknum 为 5599
  • @MatBailie 我不打算尝试第二次猜测 OP...他们可以澄清。
【解决方案3】:

在这种情况下,Inner Join 就足够了。您不需要使用交叉应用

【讨论】:

  • 答案应该完全回答问题,而不仅仅是给出更适合 cmets 的提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 2021-11-25
  • 2011-05-03
  • 2020-04-06
  • 2020-02-29
  • 1970-01-01
  • 2017-10-19
相关资源
最近更新 更多