0

How can I use either CROSS APPLY (or INNER JOIN) to get data from one table based on the values in other tables?

I.e. I have the following tables:

Table Descriptions:

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

Table Products:

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

Table Invoices:

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

What I need my query to do is to:

  1. Go into Invoices table first, and get only records that matches specified InvoiceID and TrackNum;
  2. Then go into Products table and get only rows that have matches on ProdID between the data I pulled out in Step #1 and the data existis in the Products table.
  3. Then finally get all columns from the Descriptions table, but only for the rows which I got in the Step #2 and which matches on ProdID.

What I need to have at the end is something like this (if I get more columns that is fine, but I do not want to get more rows):

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

I have following query (and I have tried using INNER JOIN and CROSS APPLY) - but it returns me more rows than I need:

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
KVN
  • 863
  • 1
  • 17
  • 35
  • You have no conditions, anywhere, stating which Description record associates to which Invoices record. So, you're applying all of the invoices you find, to every single description. – MatBailie Mar 08 '21 at 21:53
  • This might help... https://stackoverflow.com/questions/1139160/when-should-i-use-cross-apply-over-inner-join – Isaac Mar 08 '21 at 21:53
  • Looks like you might be able to use [where exists](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/exists-transact-sql?view=sql-server-ver15) instead of a join or cross apply – David784 Mar 08 '21 at 21:58

3 Answers3

1

Based on what you describe you want the following, start with your Invoices table and a where clause to get the right rows, then join on Products and Descriptions.

I'm also guessing that you want to match the Description on TrackNum? Since it appears you have a unique Description per ProdId/TrackNum combination.

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;

Note: You normally only use a 'CROSS APPLY' for queries where you want to run/evaluate something per row in your main table.

MatBailie
  • 83,401
  • 18
  • 103
  • 137
Dale K
  • 25,246
  • 15
  • 42
  • 71
  • Might want to make it `select distinct [INV].[ProdID], [DES].[Description], [INV].[TrackNum]`, to ensure no duplicates from the joins – David784 Mar 08 '21 at 21:53
  • 1
    @David784 I'm not a fan of distinct, IMO using `distinct` means one hasn't designed the query correctly. If duplicate products are possible the I'd group. But will wait to see what OP says. – Dale K Mar 08 '21 at 21:55
  • Might need to be LEFT JOIN as the invoices have tracknum 499 but one description has tracknum 5599 – MatBailie Mar 08 '21 at 22:12
  • 1
    @MatBailie I'm not going to try and second guess OP... they can clarify. – Dale K Mar 08 '21 at 22:19
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

One thing that concerns me is that both the invoices and descriptions have a column named tracknum, but your query and expected data indicate that you don't want to include that in the join? That's very confusing and either a poor column name, or a mistake in your query and example results.

MatBailie
  • 83,401
  • 18
  • 103
  • 137
  • @DaleK Thanks for the edit, but I had caps to emphasise the word Don't ;) Changed to bold instead... (Feel free to correct typos though, I am doing this on my phone, so it's very prone to smelling pistakes.) – MatBailie Mar 08 '21 at 22:16
  • That is the delema, I need the ProdID = 004 without a Description (even though it is TrackNum = 5599) to be in my final output. But if I use AND d.tracknum = i.tracknum - then this row will not be in the final, and if I do not use this - it will return too many rows :( – KVN Mar 08 '21 at 22:24
  • Thanks, folks! I missed the LEFT part. That is what I needed! – KVN Mar 08 '21 at 22:34
-1

In this case the Inner Join is sufficient. You don't need to use Cross Apply

Adil Deveci
  • 49
  • 1
  • 6
  • 1
    Answers should fully answer the question, not just give tips which are more suited to comments. – Dale K Mar 08 '21 at 21:59