Subtract from purchase and sale s table for found balance - sql

I have two tables: table one Purchase and another sales table, actually I need balance using subtract two table, subtract sales from table Purchase. My code is given below
create table purchase(
id number(10) primary key,
name varchar2(10),
p_qty number(10)
);
and insert data :
insert into purchase values(01,'productB',235);
insert into purchase values(04,'productC',394);
insert into purchase values(05,'productD',381);
insert into purchase values(08,'productE',357);
insert into purchase values(09,'productF',389);
insert into purchase values(10,'productQ',336);
another table: Sales
create table sales(
id number(10),
s_qty number(10),
constraint pid_pk foreign key (id)REFERENCES purchase(id)
);
insert data to salse table :
insert into sales values(01,34);
insert into sales values(04,54);
insert into sales values(05,44);
insert into sales values(09,50);
insert into sales values(01,3);
insert into sales values(04,4);
insert into sales values(05,5);
insert into sales values(09,53);
insert into sales values(01,2);
insert into sales values(04,2);
insert into sales values(05,2);
insert into sales values(09,2);
insert into sales values(01,4);
insert into sales values(04,9);
insert into sales values(05,11);
insert into sales values(09,7);
and I have using two query
Query 1:
select id,name,sum(p_qty) as p_total from purchase group by id,name;
ID NAME P_TOTAL
5 productD 381
10 productQ 336
4 productC 394
1 productB 235
8 productE 357
9 productF 389
QUERY2:
select id,sum(s_qty) as s_total from sales group by id;`
ID S_TOTAL
1 43
4 69
5 62
9 112
NOW I Want to below the table for balance each item
ID NAME P_TOTAL S_TOTAL BALANCE
5 productD 381 62 319
4 productC 394 69 325
1 productB 235 43 192
9 productF 389 112 277

Hope this helps.
SELECT p.id, p.name, p.p_total, s.s_total,
p.p_total - s.s_total AS balance
FROM (select id, name, sum(p_qty) as p_total FROM purchase
GROUP BY id, name) p
INNER JOIN (select id, sum(s_qty) as s_total FROM sales
GROUP BY id) s
ON s.ID = p.ID;

You're almost there. Take the two queries you already have and join them together:
SELECT p.ID,
p.NAME,
p.P_TOTAL,
s.S_TOTAL,
p.P_TOTAL - s.S_TOTAL AS BALANCE
FROM (select id, name, sum(p_qty) as p_total
from purchase
group by id, name) p
INNER JOIN (select id, sum(s_qty) as s_total
from sales
group by id) s
ON s.ID = p.ID
Best of luck.

I Want to below the table for balance each item
You way you want the balance for each item, but you only show the balance for the items with sales.
If you want each item that has been purchased, you can use left join with subqueries:
select p.id, p.name, p_total, coalesce(s_total, 0),
(p_total - coalesce(s_total, 0)) as balance
from (select id, name, sum(p_qty) as p_total
from purchase
group by id,name
) p left join
(select id, sum(s_qty) as s_total
from sales
group by id
) s
on p.id = s.id;
If you want each item that has sales, then just use inner join.

Related

How to insert data in a table from two not-connected tables SQL ORACLE?

I am working with a Data Base with 3 tables:
CREATE TABLE SALE_DETAIL
( S_SALE NUMBER,
S_NUMBER NUMBER,
S_ARTICLE VARCHAR2(30),
S_COUNT NUMBER
);
CREATE TABLE SALE
( SALE_ID NUMBER,
SALE_COMPANY VARCHAR2(30)
);
CREATE TABLE SELL
( SELL_ARTICLE VARCHAR2(30),
SELL_COUNT NUMBER
);
SALE and SELL are tables not connected to each other and they had some data and SALE_DETAIL is empty:
INSERT INTO SALE (SALE_ID, SALE_COMPANY) VALUES (1, 'Company1');
INSERT INTO SALE (SALE_ID, SALE_COMPANY) VALUES (2, 'Company1');
INSERT INTO SALE (SALE_ID, SALE_COMPANY) VALUES (3, 'Company2');
INSERT INTO SALE (SALE_ID, SALE_COMPANY) VALUES (4, 'Company3');
INSERT INTO SALE (SALE_ID, SALE_COMPANY) VALUES (5, 'Company2');
INSERT INTO SELL (SELL_ARTICLE,SELL_COUNT) VALUES ('ART1', 100);
INSERT INTO SELL (SELL_ARTICLE,SELL_COUNT) VALUES ('ART2', 50);
INSERT INTO SELL (SELL_ARTICLE,SELL_COUNT) VALUES ('ART1', 100);
INSERT INTO SELL (SELL_ARTICLE,SELL_COUNT) VALUES ('ART3', 200);
INSERT INTO SELL (SELL_ARTICLE,SELL_COUNT) VALUES ('ART3', 100);
I would like to fill SALE_DETAIL TABLE with data from SALE and SELL table which are not connected to each other.
S_SALE = SALE_ID --taken from SALE table
S_NUMBER = ROWID (sequential number starting from 1)
S_ARTICLE = SELL_ARTICLE -- taken from SELL table
S_COUNT = SELL_COUNT -- taken from SELL table
If SALE and SELL table were connected ...I tried this code
INSERT INTO SALE_DETAIL(S_SALE,S_NUMBER,S_ARTICLE,S_COUNT)
SELECT s.SALE_ID, ROWID, d.SELL_ARTICLE, d.SELL_COUNT FROM SALE s JOIN SELL d
ON (here I could code the connection beetween tha tables)
but How can I do it if they are not connected?
Join them virtually. How? For example, using row_number function, you can create a common column which is then used in join. Something like this:
SQL> insert into sale_detail (s_sale, s_number, s_article, s_count)
2 with
3 t_sale as
4 (select sale_id,
5 row_number() over (order by sale_id) rn
6 from sale),
7 t_sell as
8 (select sell_article,
9 sell_count,
10 row_number() over (order by rowid) rn
11 from sell)
12 select a.sale_id,
13 a.rn,
14 e.sell_article,
15 e.sell_count
16 from t_sale a join t_sell e on e.rn = a.rn;
5 rows created.
Result:
SQL> select * from sale_detail;
S_SALE S_NUMBER S_ARTICLE S_COUNT
---------- ---------- ------------------------------ ----------
1 1 ART1 100
2 2 ART2 50
3 3 ART1 100
4 4 ART3 200
5 5 ART3 100
SQL>
If number of rows in sale and sell tables isn't equal, then use outer join (you'll first have to find which table has more rows so that you'd know what to do).

Calculate multiple columns in the same table with the same ID

I have a table with orders(inside the order might be multiple products), when one or more product from the order is refunded then new row in the table created.
order_id
price
refund_amount
payment_type
account_id
0000000003
null
-$12.99
account_refund
12
0000000003
$60
null
account
12
0000000002
$60
null
account
12
0000000001
$60
null
account
3
What I want to get is the similar table for say account 12 but having sum of price and refund_amount for the same order_id
order_id
price
payment_type
account_id
0000000003
$47.01
account
12
0000000002
$60
account
12
Thank you.
Use a view instead of the second table, in which you get the columns you want using the group by command.
Like the following example:
CREATE VIEW table_2
as
select
order_id,
SUM(price) as price,
payment_type,
account_id
from table_1
GROUP BY order_id,
payment_type,
account_id
and then use it as a table:
select * from table_2
where account_id = 12 -- or any account_id you like

Calculate total price from data of 2 tables

I have data like:
Table SALE:
PR_KEY TRAN_ID TRAN_NO TRAN_DATE CUSTOMER_ID USER_ID TABLE_ID PAY_TYPE_ID TOTAL_PRICE
-------------------------------------------------------------------------------------------
187 SALE 130511164 2012-05-27 0000 ADMIN 59 1 0
Table Sale_detail
PR_KEY FR_KEY LIST_ORDER ITEM_ID PRICE AMOUNT
--------------------------------------------------------------
281 187 0.0000 9 10000 3
282 187 0.0000 tom 20000 2
My question is:
Are there any ways for me to push data to sale.totalprice by calculating (SD.Price * SD.Amount)+(SD.Price * SD.Amount) (for the same FR_KEY)
Or create a view to show the total price, same calculation (SD.Price * SD.Amount)+ (SD.Price * SD.Amount) (for each FR_KEY)
This is for SQL Server, and FR_KEY of sale_detail references the Pr_key of the Sale table.
I tried -
SELECT dbo.SALE_DETAIL.PR_KEY,
dbo.SALE_DETAIL.FR_KEY,
SUM(dbo.SALE_DETAIL.PRICE * dbo.SALE_DETAIL.AMOUNT) AS Grand_total
FROM dbo.SALE_DETAIL, dbo.SALE JOIN SALE s
on s.PR_KEY = SALE_DETAIL.FR_KEY
WHERE SALE_DETAIL.PR_KEY = #FR_KEY
ORDER BY PR_KEY
The result I want is:
PR_KEY TRAN_ID USER_ID TABLE_ID PAY_TYPE_ID TOTAL_PRICE
187 SALE ADMIN 59 1 70000
The query that you have provided can be simplified to:
SELECT sd.PR_KEY, sd.FR_KEY,
SUM(sd.PRICE * sd.AMOUNT) AS Grand_total
FROM dbo.SALE_DETAIL sd
on s.PR_KEY = SALE_DETAIL.FR_KEY
WHERE sd.PR_KEY = #FR_KEY
GROUP BY sd.PR_KEY, sd.FR_KEY;
No JOIN is necessary. But GROUP BY is.
You can try query below for your second question.
SELECT
SALE.PR_KEY,
TRAN_ID,
TRAN_NO,
TRAN_DATE,
CUSTOMER_ID,
USER_ID,
TABLE_ID,
PAY_TYPE_ID,
SUM(PRICE*AMOUNT) AS TOTAL_PRICE
FROM
SALE_DETAIL
INNER JOIN SALE
ON SALE_DETAIL.FR_KEY = SALE.PR_KEY
GROUP BY
SALE.PR_KEY,
TRAN_ID,
TRAN_NO,
TRAN_DATE,
CUSTOMER_ID,
USER_ID,
TABLE_ID,
PAY_TYPE_ID
Perfect oppertunity to use OUTER APPLY
SELECT
PR_KEY,
FR_KEY,
O.Grand_total
FROM dbo.SALE OUTER APPLY
(
SELECT SUM(PRICE * AMOUNT) AS Grand_total FROM SALE_DETAIL WHERE FR_KEY =PR_KEY
GROUP BY FR_KEY
) O
WHERE PR_KEY = #FR_KEY
ORDER BY PR_KEY

Counting the amount of relations to one table to another

Very hard to create a good title for this.
Given the table products
productID
---------
892
583
388
And the table purchases
customerID productID
---------- ---------
56 892
97 388
56 583
56 388
97 583
How would I go about getting a table of all the costumers that have bought all products?
You can use group by and having:
select customerId
from purchases
group by customerId
having count(distinct productID) = (select count(*) from products);
Use GROUP BY clause with HAVING :
SELECT pr.customerID
FROM products p INNER JOIN
purchases pr
on pr.productID = p.productID
GROUP BY pr.customerID
HAVING COUNT(DISTINCT pr.productID) = (SELECT COUNT(*) FROM products);

Cross-multiplying table

I have this SQL code and I want to show the sum of each item on its charge slip and on their receipt:
select item_description, sum(receipt_qty) as Samp1, sum(chargeSlip_qty) as Samp2
from Items inner join Receipt_Detail on (Receipt_Detail.item_number =
Items.item_number)
inner join ChargeSlip_Detail on (ChargeSlip_Detail.item_number =
Items.item_number)
group by item_description
It produces this output:
Acetazolamide 2681 1730
Ascorbic Acid 1512 651
Paracetamol 1370 742
Silk 576 952
But it should be:
Acetazolamide 383 173
Ascorbic Acid 216 93
Paracetamol 274 106
Silk 96 238
What's wrong with my code?
Since you are joining tables, you might have a one-to-many relationship that is causing the problem when you then get the sum(). So you can use subqueries to get the result. This will get the sum() for the receipt and chargeslip for each item_number and then you join that back to your items table to get the final result:
select i.item_description,
r.Samp1,
c.Samp2
from Items i
inner join
(
select sum(receipt_qty) Samp1,
item_number
from Receipt_Detail
group by item_number
) r
on r.item_number = i.item_number
inner join
(
select sum(chargeSlip_qty) Samp2,
item_number
from ChargeSlip_Detail
group by item_number
) c
on c.item_number = i.item_number
Do the GROUP BYs first, per Item_Number, so you don't multiply out rows from Receipt_Detail and ChargeSlip_Detail. That is, you generate the SUM values per Item_Number before JOINing back to Items
select
I.item_description,
R.Samp1,
C.Samp2
from
Items I
inner join
(SELECT item_number, sum(receipt_qty) as Samp1
FROM Receipt_Detail
GROUP BY item_number
) R
on (R.item_number = I.item_number)
inner join
(SELECT item_number, sum(chargeSlip_qty) as Samp2
FROM ChargeSlip_Detail
GROUP BY item_number
) C
on (C.item_number = I.item_number)
A left join returns rows from the left table, and for each row in the left table, all matching rows in the right table.
So for example:
create table Customers (name varchar(50));
insert Customers values
('Tim'),
('John'),
('Spike');
create table Orders (customer_name varchar(50), product varchar(50));
insert Orders values (
('Tim', 'Guitar'),
('John', 'Drums'),
('John', 'Trumpet');
create table Addresses (customer_name varchar(50), address varchar(50));
insert Addresses values (
('Tim', 'Penny Lane 1'),
('John', 'Abbey Road 1'),
('John', 'Abbey Road 2');
Then if you run:
select c.name
, count(o.product) as Products
, count(a.address) as Addresses
from Customers c
left join Orders o on o.customer_name = c.name
left join Addresses a on a.customer_name = c.name
group by name
You get:
name Products Addresses
Tim 1 1
John 4 4
Spike 0 0
But John doesn't have 4 products!
If you run without the group by, you can see why the counts are off:
select *
from Customers c
left join Orders o on o.customer_name = c.name
left join Addresses a on a.customer_name = c.name
You get:
name customer_name product customer_name address
Tim Tim Guitar Tim Penny Lane 1
John John Drums John Abbey Road 1
John John Drums John Abbey Road 2
John John Trumpet John Abbey Road 1
John John Trumpet John Abbey Road 2
Spike NULL NULL NULL NULL
As you can see, the joins end up repeating each other. For each product, the list of addresses is repeated. That gives you the wrong counts. To solve this problem, use one of the excellent other answers:
select c.name
, o.order_count
, a.address_count
from Customers c
left join
(
select customer_name
, count(*) as order_count
from Orders
group by
customer_name
) o
on o.customer_name = c.name
left join
(
select customer_name
, count(*) as address_count
from Addresses
group by
customer_name
) a
on a.customer_name = c.name
The subqueries ensure only one row is joined per customer. The result is much better:
name order_count address_count
Tim 1 1
John 2 2
Spike NULL NULL