Selecting row from group of row based on a column value [duplicate] - sql

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Closed 4 years ago.
Have following table
PkId ProfileId Status Amount
1 234 0 10
2 235 1 100
3 236 0 50
4 236 1 80
5 237 0 70
For row number 3 and 4 Profile Id is same but I want in resultset it should consider row having value 0 so whereever we have rows where Profile Id is same it should pick row where status =0 And for rest of the rows it should pick as it is.
Expected Result Set:
PkId ProfileId Status Amount
1 234 0 10
2 235 1 100
3 236 0 50
5 237 0 70
In expected result set row number 4 has to be omitted because :
236 Id at 4 is already there row number 3
Value of Status is 1 in row number 4.

you could use a join on subselect for min status
select * from my_table m
inner join (
select ProfileId , min(Status ) min_status
from my_table
group by ProfileId
) t on t.profileId = m.profileId and t.min_status = m.status

Related

Add flag on SQL Server table, based on pair of features [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 8 months ago.
I have a table in SQL Server with Id, Code and Prod. I want to add a flag and end up like:
Id Code Prod Flag
0 101 A 0
1 101 B 0
2 101 A 1
3 101 A 1
4 101 B 1
5 160 B 0
6 160 A 0
7 160 B 1
8 190 A 0
9 190 B 0
For each pair Code-Prod (eg. 101-A, which has 3 cases), the flag should assume 0 for the first Id, 1 otherwise.
How do I do that?
This is ideally solved with row_number() window function, combined with an updatable CTE:
with upd as (
select *, Row_Number() over(partition by Concat(code,prod) order by id) rn
from t
)
update upd
set flag = case when rn = 1 then 0 else 1 end;

Select values that are within a certain range but exclude the values that determine the range in Sqlite

In a SQLite local database, I have a 2 column-table, one containing values, and one containing categories. I want to update the categories of certain rows based on the following selection:
select the rows that are in a certain category
determine the values for those rows.
select the rows that have values within a certain range of the values of the already selected rows.
update the rows that are within the second selection, but exclude those that are in the first selection.
The statement that I have now (that does not work) is as follows:
UPDATE table SET category = '3' WHERE
(
value BETWEEN
(
((SELECT value FROM table WHERE category = '2') +4)
AND
((SELECT value FROM table WHERE category = '2') -4)
EXCEPT SELECT value FROM table WHERE category = '2'
)
... (further constraints)
)
This runs without error, but does not actually appear to select anything, as nothing is updated. What is the correct way to get this update to work?
EDIT: as requested an example with tables:
rowid
Value
Category
1
20
2
2
30
2
3
40
2
4
70
2
5
5
1
6
19
1
7
26
1
8
42
1
9
49
1
10
52
1
11
71
1
12
90
1
I want the values of the rows that are currently in category 1, to be placed in category 3, based on a range of 4 around the values of the rows that are in category 2. So in this case any row that has category = 1, that has a value of either 16-24, 26-34, 36-44 or 66-74.
rowid
Value
Category
1
20
2
2
30
2
3
40
2
4
70
2
5
5
1
6
19
3
7
26
3
8
42
3
9
49
1
10
52
1
11
71
3
12
90
1
You can use EXISTS:
UPDATE tablename
SET Category = 3
WHERE Category = 1
AND EXISTS (
SELECT 1
FROM tablename t
WHERE t.Category = 2
AND tablename.Value BETWEEN t.Value - 4 AND t.Value + 4
);
See the demo.

Identify a FK which has the highest value from a list of values in its source table

I have following tables.
Part
id
name
1
Part 1
2
Part 2
3
Part 3
Operation
id
name
part_id
order
1
Op 1
1
10
2
Op 2
1
20
3
Op 3
1
30
4
Op 1
2
10
5
Op 2
2
20
6
Op 1
3
10
Lot
id
part_id
Operation_id
10
1
2
11
2
5
12
3
6
I am selecting the results from Lot table and I want to select a column last_Op which is based on the order value of the operation_id. If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
SELECT
id,
part_id,
operation_id,
last_Op
FROM Lot
expected result set based on the tables above.
id
part_id
operation_id
last_op
10
1
2
0
11
2
5
1
12
3
6
1
In above example, first row returns last_op = 0 because operation_id = 2 is associated with part_id = 1 and it has the highest order = 30. Since operation_id for this part is not pointing towards the highest order value, 0 is returned.
The other two rows return 1 because operation_id 5 and 6 are associated with part_id 2 and 3 respectively and they are pointing towards the highest 'order' value.
If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
This sounds like window functions will help:
select l.*,
(case when o.order = o.max_order then 1 else 0 end) as last_op
from lot l left join
(select o.*,
max(o.order) over (partition by o.part_id) as max_order
from operations o
) o
on l.operation_id = o.id;
Note: order is a very poor name for a column because it is a SQL keyword.

Replace a column value with random values

I want to replace values in a column with randomized values
NO LINE
-- ----
1 1
1 2
1 3
1 4
2 1
2 2
3 1
4 1
4 2
I want to randomize column NO and replace with random values. I have 5 million records and doing something like below script gives me 5 million unique NO's but as you can see NO is not unique and i want the same random value assigned for the same NO.
UPDATE table1
SET NO= abs(checksum(NewId())) % 100000000
I want my resultant dataset like below
NO LINE
------ ----
99 1
99 2
99 3
99 4
1092 1
1092 2
3456 1
41098 1
41098 2
I would recommend rand() with a seed:
UPDATE table1
SET NO = FLOOR(rand(NO) * 100000000);
This runs a slight risk of collisions, so two different NO rows could get the same value.
If the numbers do not need to be "random" you can give them consecutive values in an arbitrary order and avoid collisions:
with toupdate as (
select t1.*,
dense_rank() over (order by rand(NO), no) as new_no
from t
)
update toupdate
set no = new_no;

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