SQL Insert or Update with respect to particular column - sql

My Order table is
**O_ID Emp_ID Bill**
-------------------------------------------
1 1 20
2 1 20
3 2 10
4 3 20
5 2 10
i want to insert data in Bill table like with respect to EmpID
**Bill_ID Emp_ID TotalBill**
-------------------------------------------
1 1 40
2 2 20
3 3 20
but when new row is added in Order table
**O_ID Emp_ID Bill**
-------------------------------------------
1 1 20
2 1 20
3 2 10
4 3 20
5 2 10
6 3 50
updated Bill table should be like
**Bill_ID Emp_ID TotalBill**
-------------------------------------------
1 1 40
2 2 20
3 3 70
i want Insert OR Update Query.

You first need to check row exists or not, If exists then update or do insert operation.
IF NOT EXISTS ( SELECT 1 FROM Bill WHERE Bill_ID = 1 AND EMP_ID= 1 )
BEGIN
INSERT statement
END
ELSE
BEGIN
UPDATE statement
END

All you need is the simple view with the following
Create view total_bill
as
select emp_id, sum(bill) as bill from Order
group by emp_id

Related

How to add a condition to count function in PostgreSQL

I have these tables Course, subscription,subscription_Course(A table that creates a relation between Course and subscription), and another with Student. I want to Select all the id_courses that have a subscription count higher than 1 but only want to count the subscriptions from different students. Example: If a Student Subscribes two times the same course I want to have a condition that enables the count function to not count more than one time in these cases
These are my tables:
Student:
idStudent(pk)
cc
nif
1
30348507
232928185
2
30338507
231428185
3
30438507
233528185
4
30323231
3232132
Subscription
idsubscription(pk)
Student(fk)
value_subscription
vouchercurso
date
1
1
100
null
2021-11-01
2
2
150
null
2021-12-11
3
3
160
null
2021-01-03
4
4
500
null
1996-11-07
5
1
900
null
2001-07-05
6
2
432
null
2021-05-09
Subscription_Course
idsubscription(PK/fk)
id_Course(pk/fk)
Grade
1
3
9
2
4
15
3
5
12
6
3
9
5
4
16
2
6
20
6
5
4
For example, when counting within my table Subscription_Course only the id_course:5 would have a count higher than 1 because 3 and 4 have a subscription from the same student.
I have this query for now:
Select id_Course
From Subscription_Course
Group by id_Course
Having Count (id_Course)>1
I don't know what to do to add this condition to the count.
seems like you need to join to Subscription and count unique Student id's:
select id_Course
from Subscription_Course sc
join Subscription s
on s.idsubscription = sc.idsubscription
group by id_Course
having Count(distinct Studentid)>1
You can join the Subscription_Course table with the Subscription table in order to access the id_Student column. Then just count the distinct id_Student values for each id_Course value.
SELECT
Subscription_Course.id_Course,
COUNT(DISTINCT Subscription.id_Student) AS student_count
FROM Subscription_Course
INNER JOIN Subscription
ON Subscription_Course.id_Subscription = Subscription.id_Subscription
GROUP BY Subscription_Course.id_Course
HAVING COUNT(DISTINCT Subscription.id_Student) > 1
ORDER BY student_count DESC;
With result:
id_course | student_count
-----------+---------------
3 | 2
4 | 2
5 | 2

Generate a serial number based on quantity column in sql

Hi Experts I have a table like this
T1
Order_no
Qty
1
3
2
5
3
1
4
3
I need to generate a column 'serial no' having values based on 'qty'
Output needed
OrderNo
Qty
SerailNo
1
3
1
1
3
2
1
3
3
2
5
1
2
5
2
2
5
3
2
5
4
2
5
5
3
1
1
4
3
1
4
3
2
4
3
3
Any suggestions?
Thanks in advance!!
You don't mention the specific database so I'll assume you are using PostgreSQL, aren't you?
You can use a Recursive CTE to expand the rows. For example:
with recursive
n as (
select order_no, qty, 1 as serial_no from t1
union all
select order_no, qty, serial_no + 1
from n
where serial_no < qty
)
select * from n order by order_no, serial_no
Result:
order_no qty serial_no
--------- ---- ---------
1 3 1
1 3 2
1 3 3
2 5 1
2 5 2
2 5 3
2 5 4
2 5 5
3 1 1
4 3 1
4 3 2
4 3 3
See running example at DB Fiddle.
EDIT FOR ORACLE
If you are using Oracle the query changes a bit to:
with
n (order_no, qty, serial_no) as (
select order_no, qty, 1 from t1
union all
select order_no, qty, serial_no + 1
from n
where serial_no < qty
)
select * from n order by order_no, serial_no
Result:
ORDER_NO QTY SERIAL_NO
--------- ---- ---------
1 3 1
1 3 2
1 3 3
2 5 1
2 5 2
2 5 3
2 5 4
2 5 5
3 1 1
4 3 1
4 3 2
4 3 3
See running example at db<>fiddle.
You should first provide the database you're using. Whether it's oracle, Sql Server, PostGreSQL will determine which procedural language to use. It's very likely that you'll need to do this in two steps:
1st: Duplicate the number of rows based on the column Qty using a decreasing loop
2nd: You'll need to create a sequential partionned column based on the Qty column

Add position column based on order by - Oracle

I have this table with the following records:
table1
id ele_id_1 ele_val ele_id_2
1 2 123 1
1 1 abc 1
1 4 xyz 2
1 4 456 1
2 5 22 1
2 4 344 1
2 3 6 1
2 2 Test Name 1
2 1 Hello 1
I am trying to add position for each id when ele_id_1 and ele_id_2 is order by ASC.
Here is the output:
id ele_id_1 ele_val ele_id_2 position
1 2 123 1 2
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 3
2 5 22 1 5
2 4 344 1 4
2 3 6 1 3
2 2 Test Name 1 2
2 1 Hello 1 1
I have 34 million rows in table1, so would like to use an efficient way of doing this.
Any idea on how I can add position with values?
I think you want row_number() used like this:
select row_number() over (partition by id
order by ele_id_1, ele_id_2
) as position
Oracle can use an index for this, on (id, ele_id_1, ele_id_2).
I should note that for your example data order by ele_id_1, ele_id_2 and order by ele_id_2, ele_id_1 produce the same result. Your question suggests that you want the first.
So, you would get
id ele_id_1 ele_val ele_id_2 position
1 1 123 2 2
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 3
Rather than:
id ele_id_1 ele_val ele_id_2 position
1 1 123 2 3
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 2
EDIT:
If you want to update the data, then merge is probably the best approach.
MERGE INTO <yourtable> dest
USING (select t.*,
row_number() over (partition by id
order by ele_id_1, ele_id_2
) as new_position
from <yourtable> t
) src
ON dest.id = src.id AND
dest.ele_id_1 = src.ele_id_1 AND
dest.ele_id_2 = src.ele_id_2
WHEN MATCHED THEN UPDATE
SET desc.postition = src.new_position;
Note that updating all the rows in a table is an expensive operation. Truncating the table and recreating it might be easier:
create table temp_t as
select t.*,
row_number() over (partition by id
order by ele_id_1, ele_id_2
) as new_position
from t;
truncate table t;
insert into t ( . . . )
select . . . -- all columns but position
from temp_t;
However, be very careful if you truncate the table. Be sure to back it up first!

Multiply newly entered row with another column value and find Total Sum in SQL

I have 4 tables here, I need to multiply newly entered row value in a table with another row and find the total sum using CustomerId:
CustomerTable:
CustomerId Name EmailId
-------------------------
1 Paul r#r.com
2 John J#j.com
LoyaltyPointTable:
LoyaltyPointsId LoyaltyType Points
---------------------------------------
1 Registration 10
2 Loginstatus 1
3 Downloading 10
4 Redemming 1
5 Sharing 20
6 Refer 10
LoyaltyDetailsTable:
LoyaltyDetailsId LoyaltyPointsId CustomerId Dates
-------------------------------------------------
1 1 1 2015-01-22
2 2 1 2015-01-22
3 3 2 2015-01-22
4 3 1 2015-01-22
5 4 1 2015-01-22
6 4 1 2015-01-24
7 5 1 2015-01-24
This query works fine for the total sum for each LoyaltyType
SELECT
LoayaltyPointsTable.LoyaltyType,
COUNT(CustomerTable.CustomerId) AS UserActions,
SUM(LoayaltyPointsTable.Points) AS TotalPoints
FROM
LoayaltyPointsTable
JOIN
LoyaltyDetailsTable ON LoayaltyPointsTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoayaltyPointsTable.LoyaltyType
below RedeemPointsTable is created with relation to row redeeming in LoyaltyPointTable:
RedeemPointsTable:
RedeemPointsId CustomerId ShopName BillNo Amount
------------------------------------------------
1 1 Mall x 4757 100
3 1 Mall y SH43 50
4 1 Mall x 7743 10
6 1 Mall x s34a 60
What I am expecting is before calculating the total sum, I want column Amount sum (100+50+10+60) * 1 in Redeeming in LoyaltyPointTable to be added with total points for each CustomerId
Expected output
LoyaltyType UserActions TotalPoints
-------------------------------------
Downloading 1 10
Loginstatus 1 1
Redemming 4 (100+50+10+60)*1(here using Amount in RedeemPointsTable)
Refer 1 10
Registration 1 10
Sharing 1 20
User actions count is 4, it is based on the Amount he entered in RedeemPointsTable
Should I need to make changes in adding a foreign key column in RedeemPointsTable or can you point out my mistake?
Any help would be great.
This is the query which returns desired result:
SELECT
LoyaltyPointTable.LoyaltyType,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT COUNT(amount) FROM RedeemPointsTable where CustomerId=1)
ELSE COUNT(CustomerTable.CustomerId)
END as UserActions,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT SUM(amount) FROM RedeemPointsTable where CustomerId=1)*Points
ELSE SUM(LoyaltyPointTable.Points)
END as TotalPoints
FROM
LoyaltyPointTable
JOIN
LoyaltyDetailsTable ON LoyaltyPointTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoyaltyPointTable.LoyaltyType
You can check it here

Inserting a new indicator column to tell if a given row maximizes another column in SQL

I currently have a table in SQL that looks like this
PRODUCT_ID_1 PRODUCT_ID_2 SCORE
1 2 10
1 3 100
1 10 3000
2 10 10
3 35 100
3 2 1001
That is, PRODUCT_ID_1,PRODUCT_ID_2 is a primary key for this table.
What I would like to do is use this table to add in a row to tell whether or not the current row is the one that maximizes SCORE for a value of PRODUCT_ID_1.
In other words, what I would like to get is the following table:
PRODUCT_ID_1 PRODUCT_ID_2 SCORE IS_MAX_SCORE_FOR_ID_1
1 2 10 0
1 3 100 0
1 10 3000 1
2 10 10 1
3 35 100 0
3 2 1001 1
I am wondering how I can compute the IS_MAX_SCORE_FOR_ID_1 column and insert it into the table without having to create a new table.
You can try like this...
Select PRODUCT_ID_1, PRODUCT_ID_2 ,SCORE,
(Case when b.Score=
(Select Max(a.Score) from TableName a where a.PRODUCT_ID_1=b. PRODUCT_ID_1)
then 1 else 0 End) as IS_MAX_SCORE_FOR_ID_1
from TableName b
You can use a window function for this:
select product_id_1,
product_id_2,
score,
case
when score = max(score) over (partition by product_id_1) then 1
else 0
end as is_max_score_for_id_1
from the_table
order by product_id_1;
(The above is ANSI SQL and should run on any modern DBMS)