Calculate total price from data of 2 tables - sql

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

Related

Find the products contributing to the 50% of the total sales using SQL SUM window Function

There are two Tables - orders and item_line
orders
order_id
created_at
total_amount
123
2022-11-11 13:40:50
450.00
124
2022-10-30 00:40:50
1500.00
item_line
order_id
product_id
product_name
quantity
unit_price
123
a1b
milo
4
100.00
123
c2d
coke
5
10.00
124
c2d
coke
150
10.00
The question is:
Find the products contributing to the 50% of the total sales.
My take on this is -
SELECT i.product_name,SUM(o.total_amount)AS 'Net Sales'
FROM item_line i
JOIN orders o on o.order_id = i.order_id
GROUP BY i.product_name
HAVING SUM(o.total_amount) = (SUM(o.total_amount)*0.5);
But this is not correct. SUM windows functions need to be used, but how?
Try the following, explanation is within the query comments:
-- find the the total sales for each product
WITH product_sales AS
(
SELECT product_id, product_name,
SUM(quantity * unit_price) AS product_tot_sales
FROM item_line
GROUP BY product_id, product_name
),
-- find the running sales percentage for each product starting from porduct with highest sales value
running_percentage AS
(
SELECT product_id, product_name, product_tot_sales,
SUM(product_tot_sales) OVER (ORDER BY product_tot_sales DESC) /
SUM(product_tot_sales) OVER () AS running_sales_percentage,
SUM(product_tot_sales) OVER () AS tot_sales
FROM product_sales
)
-- select products that have a running sales percentage less than the min(running_sales_percentage) where running_sales_percentage >= 0.5
-- this will select all of products that contributes of 0.5 of the total sales
SELECT product_id, product_name, product_tot_sales,
tot_sales,
running_sales_percentage
FROM running_percentage
WHERE running_sales_percentage <=
(
SELECT MIN(running_sales_percentage)
FROM running_percentage
WHERE running_sales_percentage >= 0.5
)
You don't need a join with orders table, all data you need is existed in the item_line table.
See demo.

Subtract from purchase and sale s table for found balance

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.

Firebird Query- Return first row each group

In a firebird database with a table "Sales", I need to select the first sale of all customers. See below a sample that show the table and desired result of query.
---------------------------------------
SALES
---------------------------------------
ID CUSTOMERID DTHRSALE
1 25 01/04/16 09:32
2 30 02/04/16 11:22
3 25 05/04/16 08:10
4 31 07/03/16 10:22
5 22 01/02/16 12:30
6 22 10/01/16 08:45
Result: only first sale, based on sale date.
ID CUSTOMERID DTHRSALE
1 25 01/04/16 09:32
2 30 02/04/16 11:22
4 31 07/03/16 10:22
6 22 10/01/16 08:45
I've already tested following code "Select first row in each GROUP BY group?", but it did not work.
In Firebird 2.5 you can do this with the following query; this is a minor modification of the second part of the accepted answer of the question you linked to tailored to your schema and requirements:
select x.id,
x.customerid,
x.dthrsale
from sales x
join (select customerid,
min(dthrsale) as first_sale
from sales
group by customerid) p on p.customerid = x.customerid
and p.first_sale = x.dthrsale
order by x.id
The order by is not necessary, I just added it to make it give the order as shown in your question.
With Firebird 3 you can use the window function ROW_NUMBER which is also described in the linked answer. The linked answer incorrectly said the first solution would work on Firebird 2.1 and higher. I have now edited it.
Search for the sales with no earlier sales:
SELECT S1.*
FROM SALES S1
LEFT JOIN SALES S2 ON S2.CUSTOMERID = S1.CUSTOMERID AND S2.DTHRSALE < S1.DTHRSALE
WHERE S2.ID IS NULL
Define an index over (customerid, dthrsale) to make it fast.
in Firebird 3 , get first row foreach customer by min sales_date :
SELECT id, customer_id, total, sales_date
FROM (
SELECT id, customer_id, total, sales_date
, row_number() OVER(PARTITION BY customer_id ORDER BY sales_date ASC ) AS rn
FROM SALES
) sub
WHERE rn = 1;
İf you want to get other related columns, This is where your self-answer fails.
select customer_id , min(sales_date)
, id, total --what about other colums
from SALES
group by customer_id
So simple as:
select CUSTOMERID min(DTHRSALE) from SALES group by CUSTOMERID

How to Retrieve Maximum Value of Each Group? - SQL

There is a table tbl_products that contains data as shown below:
Id Name
----------
1 P1
2 P2
3 P3
4 P4
5 P5
6 P6
And another table tbl_inputs that contains data as shown below:
Id Product_Id Price Register_Date
----------------------------------------
1 1 10 2010-01-01
2 1 20 2010-10-11
3 1 30 2011-01-01
4 2 100 2010-01-01
5 2 200 2009-01-01
6 3 500 2011-01-01
7 3 270 2010-10-15
8 4 80 2010-01-01
9 4 50 2010-02-02
10 4 92 2011-01-01
I want to select all products(id, name, price, register_date) with maximum date in each group.
For Example:
Id Name Price Register_Date
----------------------------------------
3 P1 30 2011-01-01
4 P2 100 2010-01-01
6 P3 500 2011-01-01
10 P4 92 2011-01-01
select
id
,name
,code
,price
from tbl_products tp
cross apply (
select top 1 price
from tbl_inputs ti
where ti.product_id = tp.id
order by register_date desc
) tii
Although is not the optimum way you can do it like:
;with gb as (
select
distinct
product_id
,max(register_date) As max_register_date
from tbl_inputs
group by product_id
)
select
id
,product_id
,price
,register_date
from tbl_inputs ti
join gb
on ti.product_id=gb.product_id
and ti.register_date = gb.max_register_date
But as I said earlier .. this is not the way to go in this case.
;with cte as
(
select t1.id, t1.name, t1.code, t2.price, t2.register_date,
row_number() over (partition by product_id order by register_date desc) rn
from tbl_products t1
join tbl_inputs t2
on t1.id = t2.product_id
)
select id, name, code, price, register_date
from cte
where rn = 1
Something like this..
select id, product_id, price, max(register_date)
from tbl_inputs
group by id, product_id, price
you can use the max function and the group by clause. if you only need results from the table tbl_inputs you even don't need a join
select product_id, max(register_date), price
from tbl_inputs
group by product_id, price
if you need field from the tbl_prducts you have to use a join.
select p.name, p. code, i.id, i.price, max(i.register_date)
from tbl_products p join tbl_inputs i on p.id=i.product_id
grooup by p.name, p. code, i.id, i.price
Try this:
SELECT id, product_id, price, register_date
FROM tbl_inputs T1 INNER JOIN
(
SELECT product_id, MAX(register_date) As Max_register_date
FROM tbl_inputs
GROUP BY product_id
) T2 ON(T1.product_id= T2.product_id AND T1.register_date= T2.Max_register_date)
This is, of course, assuming your dates are unique. if they are not, you need to add the DISTINCT Keyword to the outer SELECT statement.
edit
Sorry, I didn't explain it very well. Your dates can be duplicated, it's not a problem as long as they are unique per product id. if you can have duplicated dates per product id, then you will have more then one row per product in the outcome of the select statement I suggested, and you will have to find a way to reduce it to one row per product.
i.e:
If you have records like that (when the last date for a product appears more then once in your table with different prices)
id | product_Id | price | register_date
--------------------------------------------
1 | 1 | 10.00 | 01/01/2000
2 | 1 | 20.00 | 01/01/2000
it will result in having both of these records as outcome.
However, if the register_date is unique per product id, then you will get only one result for each product id.

SQL query: count for all the reviews that each customer has written

Lets say I have one table called "REVIEWS"
This table has Reviews that customers have written for various products.
I would like to be able to get a "count" for all the reviews that each customer has written,
so I write:
SELECT count(*) AS counter
FROM reviews
WHERE customers_id = 12345
Now, my problem is that I wish to have a count like above BUT only for customers who have written a SPECIFIC product review
For instance,
SELECT customers_review
FROM reviews
WHERE
products_id = '170'
In summary, I wish to be able to get the customers TOTAL COUNT for every review they have written, but ONLY for customers who have written a review for a specific product.
select customers_id, count(*)
from reviews
where customers_id in
(select customers_id from reviews where products_id = '170')
group by customers_id;
SELECT customers_id, COUNT(*) AS counter
FROM reviews
WHERE customers_id IN(
SELECT customers_id
FROM reviews
WHERE
products_id = '170'
)
GROUP BY customers_id
This will pull any customer who wrote about product X, and then count up total number of reviews they posted.
Select customer_ID, Count(*)
FROM reviews
WHERE customer_ID in ( Select Customer_ID from reviews where products_id = '170')
Group By customer_ID
This should give you a list of all CustomerID's along with the Count of all their reviews, but it will limit it only to the customers who have left a review for product 170.
Just add to the end of your first query
WHERE EXISTS (
SELECT 1 FROM reviews AS r
WHERE r.customers_id = reviews.customers_id
AND product_id = '170')
GROUP BY reviews.customers_id
Not disagreeing with the approaches in this thread. But I think windowing/analytic SQL offer another way of looking at this problem. You can get the counts:
Count of Reviews by Customer on this
detail row
Count of Reviews By
product on this detail row
Count of
Reviews by this customer on this
product on this detail row
Any
details (the text of the review, the
review ID etc...)
SQL Statement
SELECT
revid,
CUSTID,
PRODID,
COUNT (*) OVER (PARTITION BY custid) ByCust,
COUNT (*) OVER (PARTITION BY prodid) ByProd,
COUNT (*) OVER (PARTITION BY prodid, custid) ByCustProd
FROM customer_reviews
ORDER BY custid, prodid
--OUTPUT--
1520 106 1900 16 604 3
4650 106 1900 16 604 3
2730 106 1900 16 604 3
4640 106 3900 16 254 1
6287 110 1900 28 604 2
5849 110 1900 28 604 2
5965 110 3900 28 254 2
6117 110 3900 28 254 2