Joining two mysql resultset using left outer join - mysql

Below is the actual invoice table
After grouping it based on invoiceID, the resultset is
And actual payment table is
and its payment resultset after grouping based on invoiceID is
Now i want to join these two resultsets [Payment and Invoice table] and find the balance amount subtracting Total from Amount based on InvoiceID and for non matching records the balance column should be zero. I tried this, but didn't get the expected result.

Try something like this,
SELECT a.InvoiceID,
a.totalSum InvoiceAmount,
b.totalSum PaymentAmount,
a.totalSum - COALESCE(b.totalSum, 0) TotalBalance
FROM
(
SELECT InvoiceID, SUM(Total) totalSum
FROM InvoiceTB
GROUP BY InvoiceID
) a LEFT JOIN
(
SELECT InvoiceID, SUM(Total) totalSum
FROM paymentTB
GROUP BY InvoiceID
) b
ON a.InvoiceID = b.InvoiceID

Related

How to match up dates on 2 different tables and join to an ID table?

I have a table full of product ids and their attributes. I want to join sales data and receipt data from 2 different tables and a different row for each id and date combo. So I want the output to look like this:
I tried joining the product id table and sales table to the receipt table but I'm not sure how to get the dates from the sales and receipts table to match up. Not sure of how to approach this. Thanks!
Calculate the counts for each table and combine them usung UNION ALL
select
product_id
,sales_date
-- combine the counts from both tables
,sum(sales_count)
,sum(receipt_count)
from
(
-- get the counts for the sales table
select
product_id
,sales_date
,count(*) as sales_count
-- UNION needs the same number of columns in both Select -> adding a dummy column
-- 1st Select determines the datatype
,cast(0 as int) as receipt_count
from sales
group by product_id, sales_date
UNION ALL
-- get the counts for the receipts table
select
product_id
,receipt_date
,0
,count(*)
from receipts
group by product_id, receipt_date
) as dt
group by product_id, receipt_date
select p.product_id, s.sales_date, s.sales_count, r.receipt_count
from
products p,
(select count(*) sales_count, sales_date, product_id from sales group by 2,3) s
(select count(*) receipt_count, receipt_date, product_id from receipts group by 2,3) r
where
p.product_id = s.product_id
and p.product_id = r.product_id
and s.sales_date=r.receipt_date
;

Get the max column value for each unique ID

I have two tables, a customers and orders table.
The customers table contains a unique ID for each customer. It contains 1141 entries.
The orders table contains many entries with a customerID and a date.
I am trying to query my database and return a list of customers and the max(date) from the orders list.
SELECT *
FROM customers
INNER JOIN
(
SELECT CustomerID, max(date) as date
FROM orders
GROUP BY CustomerID
) Sub1
ON customers.id = Sub1.CustomerID
INNER JOIN orders
ON orders.CustomerID = Sub1.CustomerID
AND orders.date = Sub1.Date
However this query is returning 1726 rows instead of 1141 rows. Where is this getting extra from?
I think it's beacause ORDERS table contains same customerID multiple times, so when you join the table with CUSTOMERS, each CUSTOMER.id matches multiple rows of ORDERS.
The problem is that there are ties.
For a given customer, some place more than one order per day. So there's a possibility that occasionally some may have placed more than one order on the date that is their max date.
To fix this, you need to use MAX() or some column that is always unique in the Orders table (or at least unique within a given date). This is easy if you can depend on an auto-increment primary key in the Orders table:
SELECT *
FROM customers
INNER JOIN
(
SELECT CustomerID, max(orderid) as orderid as date
FROM orders
GROUP BY CustomerID
) Sub1
ON customers.id = Sub1.CustomerID
INNER JOIN orders
ON orders.CustomerID = Sub1.CustomerID
AND orders.orderid = Sub1.orderid
This assumes that orderid increases in lock-step with increasing dates. That is, you'll never have an order with a greater auto-inc id but an earlier date. That might happen if you allow data to be entered out of chronological order, e.g. back-dating orders.
;with cte as
(
select CustomerID, orderdate
, rn = row_number() over (partition by customerID order by orderdate desc)
from orders
)
select c.*, cte.orderdate
from customer c
join cte on cte.customerID = c.customerid
where rn =1 -- This will limit to latest orderdate

SQL: How select rows and minus from another table

how construct sql query to select rows from table "Product" and minus sum(pc) from another table "Order".
Here is schema.
Thanks!
Group your orders by the product to get the sum of the pc-column for the products.
Then join the sum onto your product table, subtract the sum of the orders from your pc-column in the product table.
SELECT
product.id_product,
(product.pc - ifnull(orders.amount, 0))
FROM
product
LEFT JOIN (
SELECT
id_product,
SUM(pc) AS amount
FROM
`Order`
GROUP BY
id_product
) AS orders ON orders.id_product = product.id_product

MySQL - Group and total, but return all rows in each group

I'm trying to write a query that finds each time the same person occurs in my table between a specific date range. It then groups this person and totals their spending for a specific range. If their spending habits are greater than X amount, then return each and every row for this person between date range specified. Not just the grouped total amount. This is what I have so far:
SELECT member_id,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50
This is retrieving the correct total and returning members spending over $50, but not each and every row. Just the total for each member and their grand total. I'm currently querying the whole table, I didn't add in the date ranges yet.
JOIN this subquery with the original table:
SELECT si1.*
FROM sold_items AS si1
JOIN (SELECT member_id
FROM sold_items
GROUP BY member_id
HAVING SUM(amount) > 50) AS si2
ON si1.member_id = si2.member_id
The general rule is that the subquery groups by the same column(s) that it's selecting, and then you join that with the original query using the same columns.
SELECT member_id, amount
FROM sold_items si
INNER JOIN (SELECT member_id,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50) spenders USING (member_id)
The query you have already built can be used as a temporary table to join with. if member_id is not an index on the table, this will become slow with scale.
The word spenders is a table alias, you can use any valid alias in its stead.
There are a few syntaxes that will get the result you are looking, here is one using an inner join to ensure that all rows returned have a member_id in the list returned by the group by and that the total is repeated for each a certain member has:
SELECT si.*, gb.total from sold_items as si, (SELECT member_id as mid,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50) as gb where gb.mid=si.member_id;
I think that this might help:
SELECT
member_id,
SUM(amount) AS amount_value,
'TOTAL' as amount_type
FROM
`sold_items`
GROUP BY
member_id
HAVING
SUM(amount) > 50
UNION ALL
SELECT
member_id,
amount AS amount_value,
'DETAILED' as amount_type
FROM
`sold_items`
INNER JOIN
(
SELECT
A.member_id,
SUM(amount) AS total
FROM
`sold_items` A
GROUP BY
member_id
HAVING
total <= 50
) AS A
ON `sold_items`.member_id = A.member_id
Results of the above query should be like the following:
member_id amount_value amount_type
==========================================
1 55 TOTAL
2 10 DETAILED
2 15 DETAILED
2 10 DETAILED
so the column amount_type would distinguish the two specific member groups
You could do subquery with EXISTS as an alternative:
select *
from sold_items t1
where exists (
select * from sold_items t2
where t1.member_id=t2.member_id
group by member_id
having sum(amount)>50
)
ref: http://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html
In case you need to group by multiple columns, you can use a composite identifier with concatenate in combination with a group by subquery
select id, key, language, group
from translation
--query all key-language entries by composite identifier...
where concat(key, '_', language) in (
--by lookup of all key-language combinations...
select concat(key, '_', language)
from translation
group by key, language
--that occur more than once
having count(*) > 1
)

MySQL nested select query performance

Is there a difference between these two queries? Like performance issues, etc?
Query 1:
select i.invoice_id,
i.total_price
from ( select invoice_id,
sum(price) as total_price
from orders
group by
invoice_id
) as i
inner join invoice
ON i.invoice_id = invoice.invoice_id
Query 2:
select invoice.invoice_id,
orders.total_price
from invoice
inner join ( select invoice_id,
sum(price) as total_price
from orders
group by
invoice_id
) orders
ON orders.invoice_id = invoice.invoice_id
Thanks!
Let me rewrite your queries without any sinifical changes:
Query 1
SELECT i.invoice_id,
i.total_price
FROM invoice INNER JOIN (
SELECT invoice_id,
sum(price) AS total_price
FROM orders
GROUP BY
invoice_id
) AS i
ON i.invoice_id = invoice.invoice_id;
Query 2:
SELECT invoice.invoice_id,
i.total_price
FROM invoice INNER JOIN (
SELECT invoice_id,
sum(price) AS total_price
FROM orders
GROUP BY
invoice_id
) AS i
ON i.invoice_id = invoice.invoice_id;
things I changed:
order of JOIN (which doesn't matter, since it is INNER)
table alias (orders to i, and I really don't understand, why you wanted to name it differently)
Now, it is obvious, that the only difference between them - the first argument in the main SELECT. Your question could have made sence (if there was index on one column and wasn't on the other, and, dependant on the query, you would not always have used both orders.invoice_id and invoice.invoice_id), but since you already retrieving the both column for INNER JOIN it doesn't.
Futhermore, these queries are redundant. As already been mentioned by #valex, your query (actually - both of them) could (and must) be simplified to this:
SELECT invoice_id,
sum(price) AS total_price
FROM orders
GROUP BY
invoice_id;
So, no, there is no differnce in perfomance. And, surely, there is no difference in resultset.
Also, I'd like you to know, that you can always use EXPLAIN for perfomance questions.
Your first query
select i.invoice_id,
i.total_price
from ( select invoice_id,
sum(price) as total_price
from orders
group by
invoice_id
) as i
inner join invoice
ON i.invoice_id = invoice.invoice_id
is equivalent by its result to:
select invoice_id,
sum(price) as total_price
from orders
group by invoice_id
To get the same result (if all invoice_id from orders exist in the invoice table) you don't need to JOIN the Invoice table just use query:
select invoice_id,
sum(price) as total_price
from orders
group by invoice_id