MySQL: Join Conditions based on a Table on a later Join - mysql

SELECT
p.Sku,
p.Barcode,
s.AmountIncl,
CASE
WHEN SUM(dl.Qty) IS NULL THEN 0
ELSE SUM(dl.Qty)
END AS Qty,
CASE
WHEN SUM(dl.SubTotal) IS NULL THEN 0
ELSE SUM(dl.SubTotal)
END AS SubTotal
FROM
Product AS p
LEFT JOIN
DocumentLine AS dl ON p.Sku = dl.Sku
LEFT JOIN
Document AS d ON dl.DocumentId = d.DocumentId
AND d.DocumentTypeEnum = 'Order'
AND d.PaymentStatusEnum = 'Paid'
LEFT JOIN
StandardPrice AS s ON p.ProductId = s.ProductId
WHERE
p.Barcode IS NOT NULL
GROUP BY p.Sku
I'm trying to get Qty and SubTotal figures grouped by Sku for Orders that have actually been paid.
These orders can be identified in the Document table with the conditions (d.DocumentTypeEnum = 'Order' & d.PaymentStatusEnum = 'Paid').
The financial data (Qty & SubTotal) live in DocumentLine.
How do I exclude orders/data in the DocumentLine table that are linked to a Document (linked via DocumentId) where DocumentTypeEnum IS NOT an 'Order', and the PaymentStatusEnum IS NOT 'Paid' ?
At this moment the DocumentLine includes Paid Orders, Failed Orders, Unpaid Orders, Pending Orders, Carts, etc. So the Qty and SubTotal data is way higher than we actually have sold/generated.
NOTE: I still want to show all Sku WHERE Barcode IS NOT NULL. So if there is no date in DocumentLine for a Sku the Qty and SubTotal values should be 0 ?
I'm querying in MySQL
Sample Data
Product
Sku | Barcode
1 | A
2 | B
3 |
4 | C
5 |
6 | D
DocumentLine
Sku | Qty | SubTotal | DocumentId
1 | 1 | 100 | 123
2 | 1 | 150 | 124
4 | 2 | 400 | 125
6 | 1 | 120 | 128
1 | 2 | 200 | 129
4 | 1 | 200 | 131
3 | 1 | 600 | 127
Document
DocumentId | DocumentTypeEnum | PaymentStatusEnum
123 | Order | Paid
124 | Cart | NotApplicable
125 | Order | Pending
126 | Cart | NotApplicable
127 | Cart | NotApplicable
128 | Order | Failed
129 | Order | Paid
130 | Cart | NotApplicable
131 | Order | Paid
Result:
Sku | Barcode | AmountIncl | Qty | SubTotal
1 | A | 50 | 3 | 300
2 | B | 60 | 0 | 0
4 | C | 40 | 1 | 200
6 | D | 80 | 0 | 0

SELECT p.Sku, p.Barcode, s.AmountIncl,
CASE WHEN SUM(doc.Qty) IS NULL THEN 0
ELSE SUM(doc.Qty)
END AS Qty,
CASE WHEN SUM(doc.SubTotal) IS NULL THEN 0
ELSE SUM(doc.SubTotal)
END AS SubTotal
FROM Product AS p
LEFT JOIN (Select dl.sku as sku, dl.qty as qty, dl.subtotal as subtotal
from DocumentLine dl, Document d where dl.DocumentId = d.DocumentId
AND d.DocumentTypeEnum = 'Order' AND d.PaymentStatusEnum = 'Paid') AS doc
ON p.Sku = doc.Sku
LEFT JOIN StandardPrice AS s ON p.ProductId = s.ProductId
WHERE p.Barcode IS NOT NULL
GROUP BY p.Sku

You can try this. just use LEFT JOIN base on Product table and filter Barcode which you want to get. with condition aggregate function to make it.
CREATE TABLE Product(
Sku INT,
Barcode VARCHAR(10)
);
INSERT INTO Product VALUES (1,'A');
INSERT INTO Product VALUES (2,'B');
INSERT INTO Product VALUES (3,'');
INSERT INTO Product VALUES (4,'C');
INSERT INTO Product VALUES (5,'');
INSERT INTO Product VALUES (6,'D');
CREATE TABLE DocumentLine(
Sku INT,
Qty INT,
SubTotal INT,
DocumentId INT
);
INSERT INTO DocumentLine VALUES (1, 1, 100,123);
INSERT INTO DocumentLine VALUES (2, 1, 150,124);
INSERT INTO DocumentLine VALUES (4, 2, 400,125);
INSERT INTO DocumentLine VALUES (6, 1, 120,128);
INSERT INTO DocumentLine VALUES (1, 2, 200,129);
INSERT INTO DocumentLine VALUES (4, 1, 200,131);
INSERT INTO DocumentLine VALUES (3, 1, 600,127);
CREATE TABLE Document(
Sku INT,
DocumentTypeEnum VARCHAR(50),
PaymentStatusEnum VARCHAR(50)
);
INSERT INTO Document VALUES (123 ,'Order', 'Paid');
INSERT INTO Document VALUES (124 ,'Cart', 'NotApplicable');
INSERT INTO Document VALUES (125 ,'Order', 'Pending');
INSERT INTO Document VALUES (126 ,'Cart', 'NotApplicable');
INSERT INTO Document VALUES (127 ,'Cart', 'NotApplicable');
INSERT INTO Document VALUES (128 ,'Order', 'Failed');
INSERT INTO Document VALUES (129 ,'Order', 'Paid');
INSERT INTO Document VALUES (130 ,'Cart', 'NotApplicable');
INSERT INTO Document VALUES (131 ,'Order', 'Paid');
Query 1:
select
p.sku,
Barcode,
SUM(case when DocumentTypeEnum = 'Order' and PaymentStatusEnum = 'Paid' then Qty else 0 end) 'Qty',
SUM(case when DocumentTypeEnum = 'Order' and PaymentStatusEnum = 'Paid' then SubTotal else 0 end) 'SubTotal'
from product p
left join DocumentLine dl on dl.sku = p.sku
left join Document d on dl.DocumentId = d.Sku
WHERE Barcode <> '' OR Barcode IS NOT NULL
group by p.sku,Barcode
Results:
| sku | Barcode | Qty | SubTotal |
|-----|---------|-----|----------|
| 1 | A | 3 | 300 |
| 2 | B | 0 | 0 |
| 4 | C | 1 | 200 |
| 6 | D | 0 | 0 |

If you don't want the document there are not Order and Paid use an INNER JOIN for Document and not left join
SELECT p.Sku
, p.Barcode
, s.AmountIncl
, CASE WHEN SUM(dl.Qty) IS NULL THEN 0
ELSE SUM(dl.Qty)
END AS Qty
, CASE WHEN SUM(dl.SubTotal) IS NULL THEN 0
ELSE SUM(dl.SubTotal)
END AS SubTotal
FROM Product AS p
LEFT JOIN DocumentLine AS dl ON p.Sku = dl.Sku
INNER JOIN Document AS d ON dl.DocumentId = d.DocumentId
AND d.DocumentTypeEnum = 'Order'
AND d.PaymentStatusEnum = 'Paid'
LEFT JOIN StandardPrice AS s ON p.ProductId = s.ProductId
WHERE p.Barcode IS NOT NULL
GROUP BY p.Sku

Related

JOIN and SUM different statement results (Wordpress-Mailster Database)

After the last update of Mailster (email marketing plugin for wordpress), they have changed the way they store the information about opens, clicks, unsubscribes...
Until now, everything was stored in two databases:
bao_posts: Like any other wordpress post, the information of the
email that is sent was there. (When the post_type = 'newsletter')
bao_mailster_actions: This is where the user's actions with the
email were stored. 1 when it was sent to a person, 2 when they
opened it, 3 when they clicked on it and 4 when they unsubscribed.
And with this query, I could get a table with all the emails and the information of their openings, clicks, unsubscribed...
SELECT bao_posts.post_modified,
bao_posts.ID,
bao_posts.post_title,
COUNT(CASE WHEN bao_mailster_actions.type = 1 then 1 ELSE NULL END) AS Number_People_Reached,
COUNT(CASE WHEN bao_mailster_actions.type = 2 then 1 ELSE NULL END) AS Opens,
COUNT(CASE WHEN bao_mailster_actions.type = 3 then 1 ELSE NULL END) AS Clicks,
COUNT(CASE WHEN bao_mailster_actions.type = 4 then 1 ELSE NULL END) AS Unsubs
FROM bao_posts
LEFT JOIN bao_mailster_actions ON bao_mailster_actions.campaign_id = bao_posts.ID
WHERE bao_posts.post_type = 'newsletter'
GROUP BY bao_posts.ID ;
*Expected result of this query at the end of the post.
Now the problem is that this setting is kept for emails before the update, but it has changed for new ones and now bao_mailster_actions is separated into:
bao_mailster_action_sent
bao_mailster_action_opens
bao_mailster_action_clicks
bao_mailster_action_unsubscribes
I know how to get the count of each of these tables like this:
SELECT bao_mailster_action_sent.campaign_id,
COUNT(bao_mailster_action_sent.count) AS Number_People_Reached
FROM bao_mailster_action_sent
GROUP BY bao_mailster_action_sent.campaign_id;
To get:
campaign_id
Number_People_Reached
9785
300
9786
305
(And so on with each of these 4 new tables).
So what I would like to do would be to join these 4 new queries to the original one. I've been trying to combine different JOINs, but I don't quite understand how to do it.
*Bearing in mind that if an email ID matches in both, I would need it to add up their clicks, opens (or whatever).
The expected outcome would be something like this (the same as the first query but with the aggregate data):
post_modified
ID
post_title
Number_People_Reached
Opens
Clicks
Unsubs
2021-04-29 13:13:03
9785
Prueba email
300
102
30
1
2021-04-30 15:12:01
9786
Segundo email
305
97
56
0
Thanks in advance!
I suggest that you use UNION ALL to join all the tables in a CTE.You can then use this in your query. I have modified the name because we cannot have to records with the same name.
> create table if not exists bao_mailster_action_sent
( campaign_id int,count int);
create table if not exists bao_mailster_action_opens
( campaign_id int,count int);
create table if not exists bao_mailster_action_clicks
( campaign_id int,count int);
create table if not exists bao_mailster_action_unsubscribes
( campaign_id int,count int);
CREATE TABLE if not exists bao_posts(
post_modified date,
ID int,
post_title varchar(50) );
insert into bao_mailster_action_sent values
(1,88),(2,4),(4,6);
insert into bao_mailster_action_opens values
(2,4),(3,5),(4,10);
insert into bao_mailster_action_clicks values
(1,3),(2,3),(4,6);
insert into bao_mailster_action_unsubscribes values
(1,4),(3,5),(4,5);
INSERT INTO bao_posts values
( '2021-03-01',1,'first post'),
( '2021-06-01',2,'second opion'),
( '2021-09-01',3,'third way'),
( '2021-12-01',4,'last post');
WITH bao_mailster_actionsent AS
( SELECT campaign_id,count, 1 type FROM
bao_mailster_action_sent
UNION ALL
SELECT campaign_id,count,2 FROM
bao_mailster_action_opens
UNION ALL
SELECT campaign_id,count,3 FROM
bao_mailster_action_clicks
UNION ALL
SELECT campaign_id,count,4 FROM
bao_mailster_action_unsubscribes)
SELECT bao_mailster_actionsent.campaign_id,
COUNT(bao_mailster_actionsent.count) AS TotalCount,
SUM(bao_mailster_actionsent.count) AS TotalNumber,
'type'
FROM bao_mailster_actionsent
GROUP BY bao_mailster_actionsent.campaign_id,'type' ;
WITH baoMailsterAction AS
( SELECT campaign_id,count, 1 type FROM
bao_mailster_action_sent
UNION ALL
SELECT campaign_id,count,2 FROM
bao_mailster_action_opens
UNION ALL
SELECT campaign_id,count,3 FROM
bao_mailster_action_clicks
UNION ALL
SELECT campaign_id,count,4 FROM
bao_mailster_action_unsubscribes)
SELECT bao_posts.post_modified,
bao_posts.ID,
bao_posts.post_title,
COUNT(CASE WHEN bao_mailster_actions.type = 1 then 1 ELSE NULL END) AS Number_People_Reached,
COUNT(CASE WHEN bao_mailster_actions.type = 2 then 1 ELSE NULL END) AS Opens,
COUNT(CASE WHEN bao_mailster_actions.type = 3 then 1 ELSE NULL END) AS Clicks,
COUNT(CASE WHEN bao_mailster_actions.type = 4 then 1 ELSE NULL END) AS Unsubs
FROM bao_posts
campaign_id | TotalCount | TotalNumber | type
----------: | ---------: | ----------: | ---:
1 | 1 | 88 | 1
2 | 1 | 4 | 1
4 | 1 | 6 | 1
2 | 1 | 4 | 2
3 | 1 | 5 | 2
4 | 1 | 10 | 2
1 | 1 | 3 | 3
2 | 1 | 3 | 3
4 | 1 | 6 | 3
1 | 1 | 4 | 4
3 | 1 | 5 | 4
4 | 1 | 5 | 4
post_modified | ID | post_title | Number_People_Reached | Opens | Clicks | Unsubs
:------------ | -: | :----------- | --------------------: | ----: | -----: | -----:
2021-03-01 | 1 | first post | 1 | 0 | 1 | 1
2021-06-01 | 2 | second opion | 1 | 1 | 1 | 0
2021-09-01 | 3 | third way | 0 | 1 | 0 | 1
2021-12-01 | 4 | last post | 1 | 1 | 1 | 1
db<>fiddle here
I finally got it to work using only the new tables that Mailster created (it seems that finally they did move all the info to the new tables with the update) and with 4 LEFT JOINS.
I leave the code in case someone else finds it useful:
SELECT P.post_modified,
P.ID,
P.post_title,
IFNULL(S.count,0) as 'Total',
IFNULL(O.count,0) as 'Aperturas',
IFNULL(C.count,0) as 'Clicks',
IFNULL(U.count,0) as 'Bajas' from bao_posts as P
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_clicks group by campaign_id) as C ON C.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_opens group by campaign_id) as O ON O.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_sent group by campaign_id) as S ON S.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_unsubs group by campaign_id) as U ON U.campaign_id = P.ID
WHERE P.post_type = 'newsletter'
ORDER BY P.post_modified ASC ;
P.S: As I expected, Mailster's support has not helped at all :'(

Sql join with sum up duplicates

1)The sample data set looks like this:
create table user(
user_id int,
name varchar(10),
surname varchar(10)
);
insert into user(user_id, name, surname) values
(1, 'a', 'aa'),
(2, 'b', 'bb'),
(3, 'c', 'cc');
create table books(
user_id int,
book_name varchar(10)
);
insert into books(user_id, book_name) values
(1, 'book1'),
(1, 'book2'),
(1, 'book3'),
(2, 'book1');
create table expanses(
id int,
user_id int,
amount_spent int,
date timestamp
);
insert into expanses(id, user_id, amount_spent, date)
values
(1,1,10, '2020-02-03'),
(2,1,10, '2020-02-03'),
(3,1,30, '2020-02-02'),
(4,1,12, '2020-02-01'),
(5,1,15, '2020-01-31'),
(6,1,13, '2020-01-15'),
(7,2,15, '2020-02-01'),
(8,3,20, '2020-02-01');
2)The result which I want:
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 77 |
Explanation: I want to count
a) how many users have book1 or book2 and
b) how much total they spend on a date between 2020-02-01 - 2020-02-03.
Now how the query should look like?
I am using MySQL version 8.
I have tried:
SELECT count(*)
, sum(amount_spend) as total_amount_spend
FROM
( select sum(amount_spend) as amount_spend
FROM expanses e
LEFT
JOIN books b
ON b.user_id = e.user_id
WHERE (b.book_name ='book1' or b.book_name ='book2')
and e.date between '2020-02-01' and '2020-02-03'
GROUP
BY e.user_id) src'
And the result is wrong because the select clause from the inside(a little bit modified to show you more clearly):
select amount_spend as amount_spend
FROM expanses
LEFT JOIN books ON books.user_id = expanses.user_id WHERE (books.book_name ='book1' or books.book_name ='book2') and expanses.date between '2020-02-01' and '2020-02-03'
3)Will return something like this:
| user_id | amount_spent | book_name |
|---------|--------------|-----------|
| 1 | 10 | book1 |
| 1 | 30 | book1 |
| 1 | 30 | book1 |
| 1 | 12 | book1 |
| 1 | 10 | book2 |
| 1 | 10 | book2 |
| 1 | 30 | book2 |
| 1 | 12 | book2 |
| 2 | 15 | book1 |
4)So if sum this up, we will get
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 139 |
5)Which is wrong, because there are duplicates.
If we add DISTINCT to sum(DISTINCT amount_spend)
it will be also wrong because it will give the following result
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 67 |
To summarize, you can see in table 3) there are some duplicates of amount_spent cause the book_name.(one to many relationships)
How to avoid duplicating amount_spent but stay with book_name?
Fiddle
select count(distinct user_id)
, sum(amount_spent)
from expanses
where expanses.date between '2020-02-01' and '2020-02-03'
and user_id in (select user_id from books where book_name in('book1','book2'))
https://www.db-fiddle.com/f/26ifPWyRRKGp9YVQXg1qje/0
Here's an idea for a)
SELECT COUNT(DISTINCT user_id) total FROM books WHERE book_name IN ('book1','book2');
Here's an idea for b)
SELECT SUM(amount_spent) total_spent
FROM expanses e
WHERE e.date BETWEEN '2020-02-01' AND '2020-02-03'
AND EXISTS
( SELECT *
FROM books b
WHERE b.user_id = e.user_id
AND b.book_name IN ('book1','book2')
);
Here's and idea for combining a) and b)
SELECT SUM(amount_spent) total_spent
, (SELECT COUNT(DISTINCT user_id) total FROM books WHERE book_name IN ('book1','book2')) total_customers
FROM expanses e
WHERE e.date BETWEEN '2020-02-01' AND '2020-02-03'
AND EXISTS
( SELECT *
FROM books b
WHERE b.user_id = e.user_id
AND b.book_name IN ('book1','book2')
);

SQL - LEFT JOIN, but I want COUNT(*) to only count the results from the INNER part of the join

I want to display the number of purchases each customer has made. If they've made 0 purchases, I want to display 0.
Desired Output:
-------------------------------------
| customer_name | number_of_purchases |
-------------------------------------
| Marg | 0 |
| Ben | 1 |
| Phil | 4 |
| Steve | 0 |
-------------------------------------
Customer Table:
-----------------------------
| customer_id | customer_name |
-----------------------------
| 1 | Marg |
| 2 | Ben |
| 3 | Phil |
| 4 | Steve |
-----------------------------
Purchases Table:
--------------------------------------------------
| purchase_id | customer_id | purchase_description |
--------------------------------------------------
| 1 | 2 | 500 Reams |
| 2 | 3 | 6 Toners |
| 3 | 3 | 20 Staplers |
| 4 | 3 | 2 Copiers |
| 5 | 3 | 9 Name Plaques |
--------------------------------------------------
My current query is as follows:
SELECT customer_name, COUNT(*) AS number_of_purchaes
FROM customer
LEFT JOIN purchases ON customer.customer_id = purchases.customer_id
GROUP BY customer.customer_id
However, since it's a LEFT JOIN, the query results in rows for customers with no purchases, which makes them part of the COUNT(*). In other words, customers who've made 0 purchases are displayed as having made 1 purchase, like so:
LEFT JOIN Output:
-------------------------------------
| customer_name | number_of_purchases |
-------------------------------------
| Marg | 1 |
| Ben | 1 |
| Phil | 4 |
| Steve | 1 |
-------------------------------------
I've also tried an INNER JOIN, but that results in customers with 0 purchases not showing at all:
INNER JOIN Output:
-------------------------------------
| customer_name | number_of_purchases |
-------------------------------------
| Ben | 1 |
| Phil | 4 |
-------------------------------------
How could I achieve my Desired Output where customers with 0 purchases are shown?
Instead of count(*) use count(purchase_id)
SELECT customer_name, COUNT(purchase_id) AS number_of_purchaes
FROM customer
LEFT JOIN purchases ON customer.customer_id = purchases.customer_id
GROUP BY customer_id,customer_name
You can try like this:
Sample Data:
create table customer(customer_id integer, customer_name varchar(20));
create table purchaser(purchaser_id varchar(20), customer_id integer, description varchar(20));
insert into customer values(1, 'Marg');
insert into customer values(2, 'Ben');
insert into customer values(3, 'Phil');
insert into customer values(4, 'Steve');
insert into purchaser values(1, 2, '500 Reams');
insert into purchaser values(2, 3, '6 toners');
insert into purchaser values(3, 3, '20 Staplers');
insert into purchaser values(4, 3, '20 Staplers');
insert into purchaser values(5, 3, '20 Staplers');
SELECT c.customer_id, c.customer_name, COUNT(p.purchaser_id) AS number_of_purchaes
FROM customer c
LEFT JOIN purchaser p ON c.customer_id = p.customer_id
GROUP BY c.customer_id;
SQL fiddle: http://sqlfiddle.com/#!9/32ff0a/2
COUNT(*) returns the number of items in a group. This includes NULL values and duplicates.
COUNT(ALL expression) evaluates expression for each row in a group, and returns the number of nonnull values.
CREATE table customer(customer_id integer , customer_name varchar(20));
create table purchases(purchase_id integer , customer_id integer , purchase_description varchar(30));
INSERT INTO customer ( customer_id, customer_name )
VALUES ( 1, 'Marg' )
, ( 2, 'Ben' )
, ( 3, 'Phil' )
, ( 4, 'Steve' );
INSERT INTO purchases ( purchase_id, customer_id, purchase_description )
VALUES ( 1, 2, '500 Reams' )
, ( 2, 3, '6 toners' )
, ( 3, 3, '20 Staplers' )
, ( 4, 3, '2 Copiers' )
, ( 5, 3, '9 Name Plaques' );
SELECT c.customer_name
, COUNT(p.purchase_id) AS number_of_purchases
FROM customer c
LEFT JOIN purchases p
ON c.customer_id = p.customer_id
GROUP BY c.customer_name
COUNT(*) counts rows. You want to count matches, so count from the second table as following:
select customer.customer_name , a.number_of_purchases from (
SELECT customer_id, COUNT(purchases.purchase_id) AS number_of_purchaes
FROM customer
LEFT JOIN purchases ON customer.customer_id = purchases.customer_id
GROUP BY customer.customer_id) as a
inner join customer on customer.customer_id=a.customer_id;
In other words, the LEFT JOIN returns a row when there is no match. That row has a NULL value for all the columns in the purchases table.
SELECT
customer_name, COUNT(purchase_id) AS number_of_purchases
FROM
customer AS c
LEFT JOIN purchases AS p ON (c.cid = p.cid)
GROUP BY c.name
Instead of count(*) use COUNT(purchases.customer_id)
SELECT customer_name, COUNT(purchases.customer_id) AS number_of_purchaes
FROM customer
LEFT JOIN purchases ON customer.customer_id = purchases.customer_id
GROUP BY customer.customer_id
SELECT c.customer_name,count(p.purchase_id)number_of_purchases FROM Customer c
LEFT JOIN
Purchases AS p ON c.customer_id = p.customer_id
GROUP BY c.customer_name

SQL Query Joins (Create view of combined sum from different table)

Hi I need a help regarding this problem. I want to create a view where it displays the summary of purchased and sold items.
Theses are my tables:
**tblfruit**
ID Name
1 Apple
2 Orange
3 mango
**tblpurchaseditems**
ID fruit_id qty amount
1 1 3 75
2 1 2 50
3 2 1 10
4 3 3 30
**tblsolditems**
ID fruit_id qty amount
1 1 2 150
2 1 2 350
3 2 1 50
4 3 2 230
5 3 1 120
I want the output :
**tblsummary**
ID fruit_id totalqtypurchased totalamountpurchased totalqtysold totalamountsold
1 1 5 125 4 500
2 2 1 10 1 50
3 3 3 30 3 350
So there are a couple of ways of doing this, either online or using a join.
Inline:
Select name, (select sum(qty) from tableb) as totalqty
From tablea
Join:
Select a.name, sum(b.qty) as totalqty
From tablea a
Join tableb b
On b.itemid = a.itemid
Group by a.name
For multiple tables things can get trickier using joins due to duplication so inline queries can work better here, for smaller queries.
select a.fruit_id,sum(b.qty),sum(b.amount),sum(c.qty),sum(c.amount)
from tblfruit a,tblpurchaseditems b,tblsolditems c
where a.fruit_id=b.fruit_id and a.fruit_id=c.fruit_id
group by a.fruit_id
From your sample data and expected result
you can try to UNION ALL to combine tblpurchaseditems and tblpurchaseditems table and make grp to spite two result set. then use condition aggregate function to get your expect result.
CREATE TABLE tblpurchaseditems(
ID INT,
fruit_id INT,
qty INT,
amount INT
);
INSERT INTO tblpurchaseditems VALUES (1,1,3,75);
INSERT INTO tblpurchaseditems VALUES (2,1,2,50);
INSERT INTO tblpurchaseditems VALUES (3,2,1,10);
INSERT INTO tblpurchaseditems VALUES (4,3,3,30);
CREATE TABLE tblsolditems(
ID INT,
fruit_id INT,
qty INT,
amount INT
);
INSERT INTO tblsolditems VALUES (1,1,2,150);
INSERT INTO tblsolditems VALUES (2,1,2,350);
INSERT INTO tblsolditems VALUES (3,2,1,50);
INSERT INTO tblsolditems VALUES (4,3,2,230);
INSERT INTO tblsolditems VALUES (5,3,1,120);
Query 1:
SELECT (#RN:=#RN+1) ID,
fruit_id,
SUM(CASE WHEN grp = 1 THEN qty END) totalqtypurchased ,
SUM(CASE WHEN grp = 1 THEN amount END) totalamountpurchased ,
SUM(CASE WHEN grp = 2 THEN qty END) totalqtysold,
SUM(CASE WHEN grp = 2 THEN amount END) totalamountsold
FROM (
select 1 grp,fruit_id,qty,amount from tblpurchaseditems
UNION ALL
SELECT 2,fruit_id,qty,amount FROM tblpurchaseditems
)t1 CROSS JOIN (SELECT #RN:=0) v
GROUP BY fruit_id
Results:
| ID | fruit_id | totalqtypurchased | totalamountpurchased | totalqtysold | totalamountsold |
|----|----------|-------------------|----------------------|--------------|-----------------|
| 1 | 1 | 5 | 125 | 5 | 125 |
| 2 | 2 | 1 | 10 | 1 | 10 |
| 3 | 3 | 3 | 30 | 3 | 30 |
NOTE
I would use a column itemGroup in table, which can represent which type.
1 mean purchaseditems
2 mean solditems
That would not need to use UNION ALL to combine two table, more make sense.
So in the table schema will look like.
CREATE TABLE tblitems(
ID INT,
fruit_id INT,
qty INT,
amount INT,
itemGroup INT
);
INSERT INTO tblitems VALUES (1,1,3,75,1);
INSERT INTO tblitems VALUES (2,1,2,50,1);
INSERT INTO tblitems VALUES (3,2,1,10,1);
INSERT INTO tblitems VALUES (4,3,3,30,1);
INSERT INTO tblitems VALUES (1,1,2,150,2);
INSERT INTO tblitems VALUES (2,1,2,350,2);
INSERT INTO tblitems VALUES (3,2,1,50 ,2);
INSERT INTO tblitems VALUES (4,3,2,230,2);
INSERT INTO tblitems VALUES (5,3,1,120,2);
Query 1:
SELECT (#RN:=#RN+1) ID,
fruit_id,
SUM(CASE WHEN itemGroup = 1 THEN qty END) totalqtypurchased ,
SUM(CASE WHEN itemGroup = 1 THEN amount END) totalamountpurchased ,
SUM(CASE WHEN itemGroup = 2 THEN qty END) totalqtysold,
SUM(CASE WHEN itemGroup = 2 THEN amount END) totalamountsold
FROM tblitems t1 CROSS JOIN (SELECT #RN:=0) v
GROUP BY fruit_id
Results:
| ID | fruit_id | totalqtypurchased | totalamountpurchased | totalqtysold | totalamountsold |
|----|----------|-------------------|----------------------|--------------|-----------------|
| 1 | 1 | 5 | 125 | 4 | 500 |
| 2 | 2 | 1 | 10 | 1 | 50 |
| 3 | 3 | 3 | 30 | 3 | 350 |

How to get the result in single row when using sub queries in SQL Server 2008?

I am trying to get a table with stage_name and its count in respective loan product. Like in below example stage_name is RCO and there are three loan product, Auto loan, Consumer loan and Credit card. Though I have used the logic and getting the right output, but in the output, I am getting the separate row for each stage_name and loan product case. I want only one row with all the three result. Please look at my code below, actual output and desired output:
SELECT
'RCO',
CASE
WHEN sq2.loan_type = 'Consumer loan'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Consumer_Loan,
CASE
WHEN sq2.loan_type = 'Auto Loan'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Auto_Loan,
CASE
WHEN sq2.loan_type = 'Credit Card'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Credit_Card
FROM
(SELECT
'RC0' AS ws_name, 'Consumer loan' AS loan_type,
COUNT(DISTINCT a.bpm_referenceno) AS user_count,
a.takenby AS user_id
FROM
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM
BM_RLOS_EXTTABLE m
WHERE
m.loan_type = 'Consumer Loan') sq1 ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE
a.winame='RCO'
GROUP BY
a.takenby
UNION
SELECT 'RC0','Auto loan',
count (DISTINCT a.bpm_referenceno), a.takenby
from
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM BM_RLOS_EXTTABLE m
WHERE m.loan_type='Auto Loan')sq1
ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE a.winame='RCO'
GROUP BY a.takenby
UNION
SELECT 'RC0','Credit Card',
count (DISTINCT a.bpm_referenceno), a.takenby
from
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM BM_RLOS_EXTTABLE m
WHERE m.loan_type='Credit Card')sq1
ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE a.winame='RCO'
GROUP BY a.takenby) sq2
GROUP BY sq2.ws_name,sq2.loan_type
Actual output:
|--------------|-------------|-------------|-------------|
| Stg_nm | Cons_ln | Auto_lan | Credit_card |
|--------------|-------------|-------------|-------------|
| RCO | NULL | NULL | 8 |
|--------------|-------------|-------------|-------------|
| RCO | NULL | 55 | NULL |
|--------------|-------------|-------------|-------------|
| RCO | 81 | NULL | NULL |
|--------------|-------------|-------------|-------------|
Required Output
|--------------|-------------|-------------|-------------|
| Stg_nm | Cons_ln | Auto_lan | Credit_card |
|--------------|-------------|-------------|-------------|
| RCO | 81 | 55 | 8 |
|--------------|-------------|-------------|-------------|
The top half should be like this - reverse the usage of SUM and CASE, and remove the last GROUP BY altogether
SELECT
'RCO',
SUM(CASE
WHEN sq2.loan_type = 'Consumer loan'
THEN sq2.user_count
ELSE 0 END
)
AS Consumer_Loan,
SUM(CASE
WHEN sq2.loan_type = 'Auto loan'
THEN sq2.user_count
ELSE 0 END
)
AS Auto_Loan,
SUM(CASE
WHEN sq2.loan_type = 'Credit Card'
THEN sq2.user_count
ELSE 0 END
)
AS Credit_Card
FROM
<your existing query, with the final GROUP BY removed>
But you need to remove the GROUP BY from the end altogether