Calculate multiple columns in the same table with the same ID - sql

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

Related

SQL retrieval from a table

Sales table
ItemID Date Code
-------------------------------------------------
12345 2019-02-17 1
12345 2019-02-17 2
12345 2019-02-17 3
-------------------------------------------------
12344 2019-02-18 1
12344 2019-02-18 3
12344 2019-02-18 2
-------------------------------------------------
12443 2019-02-19 1
12443 2019-02-19 2
12443 2019-02-19 3
I want to retrieve those item ids from Sales table where Code 2 is updated after code 3. So my query should return 12344 as result... I cannot think of any functions to achieve this as I have limited knowledge on SQL. Can someone please provide me some suggestion on achieving this? Thanks
Here is the query that you are looking for
select sales1.itemId from sales sales1
inner join sales sales2
on sales1.itemId = sales2.itemId
where sales1.date > sales2.date and sales1.code = 2 and sales2.code = 3;
Check if it helps you.
You can try using lag()
select itemid from
(
select sales1.itemId,sales1.code,
sales1.code-lag(code) over(partition by itemid order by dates) as diff
from sales sales1
where code in (2,3)
)A where diff>=1
You can include a column
update_seq_no
Each time you update you can increase the update_seq_no and then you can achieve your requirement you want using the below sql.
alter table sales add (update_seq_no number);
create SEQUENCE IFSQ_UPDATE_SEQNO MINVALUE 1000 MAXVALUE 9999999999999999 INCREMENT BY 1 START WITH 1 NOCYCLE ;
-- for existing rows (just a work around)
BEGIN
for rec in (select rowid row_id,itemid,date from sales where update_Seq_no is null order by 2,3 asc)
loop
update sales set update_Seq_no=IFSQ_UPDATE_SEQNO.NEXTVAL
where rowid=rec.row_id;
commit;
end loop;
end;
--for new rows
insert into sales values(p_itemid,p_date,3,IFSQ_UPDATE_SEQNO.NEXTVAL);
insert into sales values(p_itemid,p_date,2,IFSQ_UPDATE_SEQNO.NEXTVAL);
with sales1 as (select row_num1,a.* from (select rownum row_num1,b.*
from sales b order by update_seq_no asc)a)
select a.*
from sales1 a,sales1 b
where a.row_num1-1=b.row_num1
and a.code=2 and b.code=3
and a.itemid=b.itemid
and a.Date=b.Date;
If there is only one row per itemid and code, then you can simply aggregate:
select itemid
from mytable
group by itemid
having max(case when code = 2 then date end) > max(case when code = 3 then date end);
With your sample data, however, no itemid will be returned, as all codes per itemid have the same date. None comes before the other.

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.

Oracle SQL Help Data Totals

I am on Oracle 12c and need help with the simple query.
Here is the sample data of what I currently have:
Table Name: customer
Table DDL
create table customer(
customer_id varchar2(50),
name varchar2(50),
activation_dt date,
space_occupied number(50)
);
Sample Table Data:
customer_id name activation_dt space_occupied
abc abc-001 2016-09-12 20
xyz xyz-001 2016-09-12 10
Sample Data Output
The query I am looking for will provide the following:
customer_id name activation_dt space_occupied
abc abc-001 2016-09-12 20
xyz xyz-001 2016-09-12 10
Total_Space null null 30
Here is a slightly hack-y approach to this, using the grouping function ROLLUP(). Find out more.
SQL> select coalesce(customer_id, 'Total Space') as customer_id
2 , name
3 , activation_dt
4 , sum(space_occupied) as space_occupied
5 from customer
6 group by ROLLUP(customer_id, name, activation_dt)
7 having grouping(customer_id) = 1
8 or (grouping(name) + grouping(customer_id)+ grouping(activation_dt)) = 0;
CUSTOMER_ID NAME ACTIVATIO SPACE_OCCUPIED
------------ ------------ --------- --------------
abc abc-001 12-SEP-16 20
xyz xyz-001 12-SEP-16 10
Total Space 30
SQL>
ROLLUP() generates intermediate totals for each combination of column; the verbose HAVING clause filters them out and retains only the grand total.
What you want is a bit unusual, as if customer_id is integer, then you have to cast it to string etc, but it this is your requirement, then if be achieved this way.
SELECT customer_id,
name,
activation_dt,
space_occupied
FROM
(SELECT 1 AS seq,
customer_id,
name,
activation_dt,
space_occupied
FROM customer
UNION ALL
SELECT 2 AS seq,
'Total_Space' AS customer_id,
NULL AS name,
NULL AS activation_dt,
sum(space_occupied) AS space_occupied
FROM customer
)
ORDER BY seq
Explanation:
Inner query:
First part of union all; I added 1 as seq to give 1
hardcoded with your resultset from customer.
Second part of union
all: I am just calculating sum(space_occupied) and hardcoding other
columns, including 2 as seq
Outer query; Selecting the data
columns and order by seq, so Total_Space is returned at last.
Output
+-------------+---------+---------------+----------------+
| CUSTOMER_ID | NAME | ACTIVATION_DT | SPACE_OCCUPIED |
+-------------+---------+---------------+----------------+
| abc | abc-001 | 12-SEP-16 | 20 |
| xyz | xyz-001 | 12-SEP-16 | 10 |
| Total_Space | null | null | 30 |
+-------------+---------+---------------+----------------+
Seems like a great place to use group by grouping sets seems like this is what they were designed for. Doc link
SELECT coalesce(Customer_Id,'Total_Space') as Customer_ID
, Name
, ActiviatioN_DT
, sum(Space_occupied) space_Occupied
FROM customer
GROUP BY GROUPING SETS ((Customer_ID, Name, Activation_DT, Space_Occupied)
,())
The key thing here is we are summing space occupied. The two different grouping mechanisms tell the engine to keep each row in it's original form and 1 records with space_occupied summed; since we group by () empty set; only aggregated values will be returned; along with constants (coalesce hardcoded value for total!)
The power of this is that if you needed to group by other things as well you could have multiple grouping sets. imagine a material with a product division, group and line and I want a report with sales totals by division, group and line. You could simply group by () to get grand total, (product_division, Product_Group, line) to get a product line (product_Divsion, product_group) to get a product_group total and (product_division) to get a product Division total. pretty powerful stuff for a partial cube generation.

How to remove duplicate accounts in SQL?

I am using SQL Server 2008 and I was wondering how to remove duplicate customers either from the table or exclude it in my query. An Account_ID can only have 1 product associated with it. And the account with the most recent purchase date is what should be showing. An example is below:
Account_ID, Account_Purchase, Purchase_Date
1 Product 1 1/1/2016
2 Product 1 1/2/2016
3 Product 2 1/5/2016
1 Product 3 3/12/2016
4 Product 3 1/5/2016
Ideally I would only see:
Account_ID, Account_Purchase, Purchase_Date
2 Product 1 1/2/2016
3 Product 2 1/5/2016
1 Product 3 3/12/2016
4 Product 3 1/5/2016
This should not show up because it is not the most recent purchase from account 1
Account_ID, Account_Purchase, Purchase_Date
1 Product 1 1/1/2016
Thank you all for help, folks!
Simply acquire the latest purchase_date using max and group by account_id. Then use inner join to get the other details from the acquired details.
SELECT TABLE_NAME.* FROM TABLE_NAME
INNER JOIN(
SELECT Account_ID, MAX(Purchase_Date) AS Purchase_Date
GROUP BY Account_ID
) LatestPurchases
ON TABLE_NAME.Account_ID = LatestPurchases.Account_ID
AND TABLE_NAME.Purchase_Date = LatestPurchases.Purchase_Date
Try below query, please replace TABLENAME with your table
WITH CTE
AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Account_ID ORDER BY Purchase_Date DESC) AS RN
FROM TABLENAME
)
SELECT
*
FROM CTE
WHERE RN = 1
Here is another query
SELECT
t.Account_id,
t.Account_Purchase,
t.Purchase_Date
FROM
tablename t
WHERE
t.Purchase_Date = (SELECT MAX(Purchase_date) FROM Tablename WHERE Account_ID = t.Account_ID)
ORDER BY
t.Purchase_Date DESC

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