Reputation: 13
I have a table Invoice
that looks similar to this:
order_id | completed_at | subtotal | discount_amount | handling_amount |
---|---|---|---|---|
100 | 07/01/2021 | 10.09 | 0 | 0 |
101 | 07/04/2021 | 200.30 | 0 | 0 |
102 | 07/04/2021 | 54.10 | 0 | 0 |
103 | 07/06/2021 | 12.00 | 0 | 0 |
And I have another table InvoiceDetail
:
order_id | product_id | qty | amount |
---|---|---|---|
100 | 1234 | 1 | 1.09 |
100 | Shipping1 | 1 | 4.30 |
100 | SalesTax | 1 | .67 |
101 | 987 | 2 | 74.20 |
101 | 654 | 1 | 6.20 |
101 | Shipping2 | 1 | 5.10 |
101 | SalesTax | 1 | 2.30 |
102 | 123 | 1 | 30.15 |
102 | Shipping8 | 1 | 6.80 |
102 | SalesTax | 1 | 1.08 |
103 | 321 | 1 | 8.04 |
103 | Shipping4 | 1 | 2.05 |
103 | SalesTax | 1 | .70 |
I need to join the tables to look like this:
order_id | completed_at | subtotal | shipping | sales_tax | discount_amount | handling_amount |
---|---|---|---|---|---|---|
100 | 07/01/2021 | 10.09 | 4.30 | .67 | 0 | 0 |
101 | 07/04/2021 | 200.30 | 5.10 | 2.30 | 0 | 0 |
102 | 07/04/2021 | 54.10 | 6.80 | 1.08 | 0 | 0 |
103 | 07/06/2021 | 12.00 | 2.05 | .70 | 0 | 0 |
I have tried a few different things but every time it ends up with multiple rows for each order_id.
SELECT
order_id,
completed_at,
subtotal,
CASE
WHEN t2.product_id LIKE '%Shipping%'
THEN t2.amount
END AS shipping,
CASE
WHEN t2.product_id = 'SalesTax'
THEN t2.amount
END AS sales_tax,
discount_amount,
handling_amount
FROM
Invoice t1
INNER JOIN
InvoiceDetail t2 ON t1.order_id = t2.InvoiceDetail
WHERE
order_id BETWEEN '100' AND '103'
The above will output the information but in multiple rows for each order_id
. I need the order information combined with the shipping and salestax all in one row. How do I achieve what I'm after?
Upvotes: 1
Views: 1533
Reputation: 69769
You were close, you just need to use SUM()
around your fields from InvoiceDetail
and then GROUP BY
your fields from Invoice
:
SELECT i.order_id,
i.completed_at,
i.subtotal,
SUM(CASE WHEN id.product_id LIKE '%Shipping%' THEN id.Amount END) AS shipping,
SUM(CASE WHEN id.product_id = 'SalesTax' THEN id.Amount END) AS sales_tax,
i.discount_amount,
i.handling_amount
FROM dbo.Invoice AS i
INNER JOIN dbo.InvoiceDetail AS id
ON id.order_id = i.order_id
WHERE i.order_id BETWEEN 100 AND 103
GROUP BY i.order_id, i.completed_at, i.subtotal, i.discount_amount, i.handling_amount;
N.B I updated your join condition from t1.order_id = t2.InvoiceDetail
as this looks like an error in the question, it is presumably order_id
from both tables.
I also removed the quotes from around 100
and 103
. If order_id
is an integer then the quotes are not necessary, if order_id
is not an integer then BETWEEN
is probably not the right operator to use.
Unrelated to your question, but with SQL Server it is a good idea to get in the habit of always including the schema prefix(Except for the cases where you genuinely want to switch schemas based on the execution context). Another good habit is to use meaningful table aliases. If you are using t1
, t2
, t3
etc this quickly gets very messy when you have large queries, t4
gives me no information whatsoever about which table it might be, but if you use prefixes that relate to the table itself (e.g. i
for invoice, id
for invoice detail), then it is much clearer when reading the code which column comes from which table.
Upvotes: 1
Reputation: 48780
You can use conditional aggregation using CASE
inside a SUM()
aggregation function. For example:
select
i.order_id,
max(i.completed_at) as completed_at,
max(i.subtotal) as subtotal,
sum(case when d.product_id like 'Shipping%' then amount end) as shipping,
sum(case when d.product_id = 'SalesTax' then amount end) as sales_tax,
max(i.discount_amount) as discount_amount,
max(i.handling_amount) as handling_amount
from invoice i
left join invoicedetail d on d.order_id = i.order_id
group by i.order_id
Upvotes: 0