How to do an update on mysql database for increment values - mysql

I will give a small exemple for my problem.
I have two tables in my database.
"Car" with the rows: "id","name".
"Seats" with the rows: "cid","weight".
The weight for the seats referees to the order of the seats.A car can have from 0 to n seats.
My problem is that i have seats with the same weight on a car.
I need to do an update for every car where two or more seats have same weight.
CAR
--------------------------
id | name
--------------------------
1 | ford
--------------------------
SEATS
-------------------------------
cid | name | weight
-------------------------------
1 Seat1 | 7
1 Seat2 | 1
1 Seat3 | 7
1 Seat4 | 3
1 Seat5 | 2
1 Seat6 | 3
1 Seat N | N
-------------------------------
And i need to have:
CID is the CAR id
SEATS
-------------------------------
cid | name | weight
-------------------------------
1 Seat1 | 0
1 Seat2 | 1
1 Seat3 | 2
1 Seat4 | 3
1 Seat5 | 4
1 Seat6 | 5
1 Seat N | N
-------------------------------
The query will run on a very big database and will affect many rows, so it is need to be fast.
I have done the join on the tables, but i don`t know how to make the complete update method.
The INNER JOIN is needed for this.

You can use user-defined variables in order to achieve a serial no for your weight column
update t
join (
select `cid`, `name`,#rank:= #rank + 1 rank
from t join
(select #rank:=-1) t1
order by `cid`, `name`
) t2
using(`cid`, `name`)
set weight = t2.rank
Demo
or if you need to a serial weight no for each car group then you can do so
update t
join (
select `cid`, `name`,
#rank:=case when #group = cid
then #rank + 1
else 0 end rank,
#group:=cid
from t join
(select #rank:=-1,#group:= 0) t1
order by `cid`, `name`
) t2
using(`cid`, `name`)
set weight = t2.rank
Demo serial per group

Related

How do I update scores in table without using a ranking function

Table name is: result
ID Name score position
1 John 40 0
2. Ali 79 0
3 Ben 50 0
4 Joe 79 0
How can I update table result to give me the table below without using rank() as it does not support by server. Pls someone should help me with the MySQL code That breaks ties just as in table below.
ID Name score position
1 John 40 4
2. Ali 79 1
3 Ben 50 3
4 Joe 79 1
In MySQL prior to version 8 try using the multiple table update syntax:
UPDATE scores t
LEFT JOIN (
SELECT t1.id, COUNT(*) + 1 AS new_position
FROM scores t1
JOIN scores t2 ON t1.score < t2.score
GROUP BY t1.id
) agg ON t.id = agg.id
SET t.position = COALESCE(agg.new_position, 1)
fiddle
Lots of ways to skin this particular animal. How about...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID SERIAL PRIMARY KEY
,Name VARCHAR(12) NOT NULL
,score INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'John',40),
(2,'Ali',79),
(3,'Ben',50),
(4,'Joe',79);
SELECT id
, name
, score
, FIND_IN_SET(score, scores) rank
FROM my_table
CROSS
JOIN
( SELECT GROUP_CONCAT(score ORDER BY score DESC) scores
FROM my_table
) scores
+----+------+-------+------+
| id | name | score | rank |
+----+------+-------+------+
| 1 | John | 40 | 4 |
| 2 | Ali | 79 | 1 |
| 3 | Ben | 50 | 3 |
| 4 | Joe | 79 | 1 |
+----+------+-------+------+
I've not provided an UPDATE, because you wouldn't normally store derived data.
You can use correlated sub-query as follows:
update your_table t
set t.position = (select count(*) + 1 from your_table tt
where tt.score > t.score)

SQL Query sort and update by row number (SQLFiddle example)

I have a sports database where I want to sort the data by a custom field ('Rating') and update the field ('Ranking') with the row number.
I have tried the following code to sort the data by my custom field 'Rating'. It works when I sort it by a normal field, but not with a custom/calculated field. When the sorting has been done, I want it to update the field 'Ranking' with the row number.
Ie the fighter with the highest 'Rating' should have the value '1' as 'Ranking.
SELECT id,lastname, wins, Round(((avg(indrating)*13) + (avg(Fightrating)*5) * 20) / 2,2) as Rating,
ROW_NUMBER() OVER (ORDER BY 'Rating' DESC) AS num
from fighters
JOIN fights ON fights.fighter1 = fighters.id
GROUP BY id
The code above isn't sorting the Rating accurately. It sorts by row number, but the highest Rating isn't rated as #1. It seems a bit random.
SQL Fiddle: http://sqlfiddle.com/#!9/aa1fca/1 (This example is correctly sorted, but I want it to update the "Ranking" column by row number - meaning the highest rated fighter (by 'Rating') gets '1' in the Ranking column, the second highest reated fighter gets '2' in the Ranking column etc).
Also I would like to be able to add WHERE clause in the fighters table (where fighters.organization = 'UFC') for example.
First, let's fix your query so it runs on MySQL < 8.0. This requires doing the computing and sorting in a subquery, then using a variable to compute the rank:
select
id,
rating,
#rnk := #rnk + 1 ranking
from
(select #rnk := 0) r
cross join (
select
fighter1 id,
round(((avg(indrating)*13) + (avg(fightrating)*5) * 20) / 2,2) as rating
from fights
group by fighter1
order by rating desc
) x
Now we use the update ... join ... set ... syntax to update the fighters table:
update fighters f
inner join (
select
id,
rating,
#rnk := #rnk + 1 ranking
from
(select #rnk := 0) r
cross join (
select
fighter1 id,
round(((avg(indrating)*13) + (avg(fightrating)*5) * 20) / 2,2) as rating
from fights
group by fighter1
order by rating desc
) x
) y on y.id = f.id
set f.ranking = y.ranking;
Demo in a MySQL 5.6 fiddle based on the fiddle you provided in the comments.
The select query returns:
| id | rating | ranking |
| --- | ------ | ------- |
| 3 | 219.5 | 1 |
| 4 | 213 | 2 |
| 1 | 169.5 | 3 |
| 2 | 156.5 | 4 |
And here is the content of the fighters table after the update:
| id | lastname | ranking |
| --- | ---------- | ------- |
| 1 | Gustafsson | 3 |
| 2 | Cyborg | 4 |
| 3 | Jones | 1 |
| 4 | Sonnen | 2 |

SQL Query Joins (Create view of combined sum from different table)

Hi I need a help regarding this problem. I want to create a view where it displays the summary of purchased and sold items.
Theses are my tables:
**tblfruit**
ID Name
1 Apple
2 Orange
3 mango
**tblpurchaseditems**
ID fruit_id qty amount
1 1 3 75
2 1 2 50
3 2 1 10
4 3 3 30
**tblsolditems**
ID fruit_id qty amount
1 1 2 150
2 1 2 350
3 2 1 50
4 3 2 230
5 3 1 120
I want the output :
**tblsummary**
ID fruit_id totalqtypurchased totalamountpurchased totalqtysold totalamountsold
1 1 5 125 4 500
2 2 1 10 1 50
3 3 3 30 3 350
So there are a couple of ways of doing this, either online or using a join.
Inline:
Select name, (select sum(qty) from tableb) as totalqty
From tablea
Join:
Select a.name, sum(b.qty) as totalqty
From tablea a
Join tableb b
On b.itemid = a.itemid
Group by a.name
For multiple tables things can get trickier using joins due to duplication so inline queries can work better here, for smaller queries.
select a.fruit_id,sum(b.qty),sum(b.amount),sum(c.qty),sum(c.amount)
from tblfruit a,tblpurchaseditems b,tblsolditems c
where a.fruit_id=b.fruit_id and a.fruit_id=c.fruit_id
group by a.fruit_id
From your sample data and expected result
you can try to UNION ALL to combine tblpurchaseditems and tblpurchaseditems table and make grp to spite two result set. then use condition aggregate function to get your expect result.
CREATE TABLE tblpurchaseditems(
ID INT,
fruit_id INT,
qty INT,
amount INT
);
INSERT INTO tblpurchaseditems VALUES (1,1,3,75);
INSERT INTO tblpurchaseditems VALUES (2,1,2,50);
INSERT INTO tblpurchaseditems VALUES (3,2,1,10);
INSERT INTO tblpurchaseditems VALUES (4,3,3,30);
CREATE TABLE tblsolditems(
ID INT,
fruit_id INT,
qty INT,
amount INT
);
INSERT INTO tblsolditems VALUES (1,1,2,150);
INSERT INTO tblsolditems VALUES (2,1,2,350);
INSERT INTO tblsolditems VALUES (3,2,1,50);
INSERT INTO tblsolditems VALUES (4,3,2,230);
INSERT INTO tblsolditems VALUES (5,3,1,120);
Query 1:
SELECT (#RN:=#RN+1) ID,
fruit_id,
SUM(CASE WHEN grp = 1 THEN qty END) totalqtypurchased ,
SUM(CASE WHEN grp = 1 THEN amount END) totalamountpurchased ,
SUM(CASE WHEN grp = 2 THEN qty END) totalqtysold,
SUM(CASE WHEN grp = 2 THEN amount END) totalamountsold
FROM (
select 1 grp,fruit_id,qty,amount from tblpurchaseditems
UNION ALL
SELECT 2,fruit_id,qty,amount FROM tblpurchaseditems
)t1 CROSS JOIN (SELECT #RN:=0) v
GROUP BY fruit_id
Results:
| ID | fruit_id | totalqtypurchased | totalamountpurchased | totalqtysold | totalamountsold |
|----|----------|-------------------|----------------------|--------------|-----------------|
| 1 | 1 | 5 | 125 | 5 | 125 |
| 2 | 2 | 1 | 10 | 1 | 10 |
| 3 | 3 | 3 | 30 | 3 | 30 |
NOTE
I would use a column itemGroup in table, which can represent which type.
1 mean purchaseditems
2 mean solditems
That would not need to use UNION ALL to combine two table, more make sense.
So in the table schema will look like.
CREATE TABLE tblitems(
ID INT,
fruit_id INT,
qty INT,
amount INT,
itemGroup INT
);
INSERT INTO tblitems VALUES (1,1,3,75,1);
INSERT INTO tblitems VALUES (2,1,2,50,1);
INSERT INTO tblitems VALUES (3,2,1,10,1);
INSERT INTO tblitems VALUES (4,3,3,30,1);
INSERT INTO tblitems VALUES (1,1,2,150,2);
INSERT INTO tblitems VALUES (2,1,2,350,2);
INSERT INTO tblitems VALUES (3,2,1,50 ,2);
INSERT INTO tblitems VALUES (4,3,2,230,2);
INSERT INTO tblitems VALUES (5,3,1,120,2);
Query 1:
SELECT (#RN:=#RN+1) ID,
fruit_id,
SUM(CASE WHEN itemGroup = 1 THEN qty END) totalqtypurchased ,
SUM(CASE WHEN itemGroup = 1 THEN amount END) totalamountpurchased ,
SUM(CASE WHEN itemGroup = 2 THEN qty END) totalqtysold,
SUM(CASE WHEN itemGroup = 2 THEN amount END) totalamountsold
FROM tblitems t1 CROSS JOIN (SELECT #RN:=0) v
GROUP BY fruit_id
Results:
| ID | fruit_id | totalqtypurchased | totalamountpurchased | totalqtysold | totalamountsold |
|----|----------|-------------------|----------------------|--------------|-----------------|
| 1 | 1 | 5 | 125 | 4 | 500 |
| 2 | 2 | 1 | 10 | 1 | 50 |
| 3 | 3 | 3 | 30 | 3 | 350 |

MySQL : collect the sum of the associated values

I have three tables in database:
Table: article
id | code | name | quantity | stock_date
--------------------------------------------------
1 1dfod Article name 10 2016-04-01
Table: selling
id | client_id | selling_type_id | selling_date | selling_status
----------------------------------------------------------------
1 1 1 2016-04-02 1
2 1 1 2016-04-03 1
3 1 1 2016-04-04 1
Table: selling_detail
id | selling_id | article_id | quantity
-------------------------------------
1 1 1 2
2 1 1 3
3 1 1 1
4 2 1 3
5 3 1 1
at the end I would have a stock record for this article like this:
date | in_stock (item in stock) | out_stock (sum of item sold)
----------------------------------------------------------------------
2016-04-01 10 0
2016-04-02 0 6
2016-04-03 0 3
2016-04-04 0 1
All mysql queries to my knowledge do not give me this result.
Here is my code:
SELECT SUM(sd.quantity) out_stock, s.search_date, ifnull(ss.quantity, 0) in_stock
FROM selling_detail sd JOIN selling s ON (sd.selling_id = s.id)
LEFT JOIN shop_stock ss ON (ss.search_date = s.search_date) WHERE (sd.shop_stock_id = 1)
GROUP BY s.search_date;
SELECT date,SUM(in_stock) in_stock,SUM(out_stock) out_stock FROM
(
SELECT stock_date date,quantity in_stock,0 out_stock FROM article
UNION
SELECT selling_date,0,quantity FROM selling JOIN selling_detail ON selling_detail.selling_id = selling.id
) x
GROUP BY date;
As you are trying to combine similar data from two very different tables, you'll probably be staring down the barrel of a UNION ALL.
Something along these lines should get you started:
SELECT *
FROM (
SELECT a.stock_date `date`,
SUM(a.quantity) `in_stock (item in stock)`,
0 `out_stock (sum of item sold)`
FROM article a
WHERE a.id = :article_id
GROUP BY `date`
UNION ALL
SELECT s.selling_date,
0,
SUM(sd.quantity)
FROM selling s
JOIN selling_detail sd
ON sd.selling_id = s.id
AND sd.article_id = :article_id
/* WHERE s.selling_type = ??
AND s.selling_status = ?? /* If necessary */
GROUP BY `date`
) sr
ORDER BY `date`

retrieve value of maximum occurrence in a table

I am in a very complicated problem. Let me explain you first what I am doing right now:
I have a table name feedback in which I am storing grades against course id. The table looks like this:
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 6 | 12 | B | 3 | 3 | 3
| 7 | 11 | B+ | 2 | 7 | 8
| 8 | 11 | A+ | 1 | 1 | 2
g_point has just specific values for the grades, thus I can use these values to show the user courses sorted by grades.
Okay, now first my task is to print out the grade of each course. The grade can be calculated by the maximum occurrence against each course. For example from this table we can see the result of cid = 10 will be A+, because it is present two times there. This is simple. I have already implemented this query which I will write here in the end.
The main problem is when we talk about the course cid = 11 which has two different grades. Now in that situation client asks me to take the average of workload and easiness of both these courses and whichever course has the greater average should be shown. The average would be computed like this:
all workload values of the grade against course
+ all easiness values of the grade against course
/ 2
From this example cid = 11 has four entries,have equal number of grades against a course
B+ grade average
avgworkload(2 + 7)/2=x
avgeasiness(3 + 8)/2 = y
answer x+y/2 = 10
A+ grade average
avgworkload(5 + 1)/2=x
avgeasiness(4 + 2)/2 = y
answer x+y/2 = 3
so the grade should be B+.
This is the query which I am running to get the max occurrence grade
SELECT
f3.coursecodeID cid,
f3.grade_point p,
f3.grade g
FROM (
SELECT
coursecodeID,
MAX(mode_qty) mode_qty
FROM (
SELECT
coursecodeID,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f1
GROUP BY coursecodeID
) f2
INNER JOIN (
SELECT
coursecodeID,
grade_point,
grade,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f3
ON
f2.coursecodeID = f3.coursecodeID AND
f2.mode_qty = f3.mode_qty
GROUP BY f3.coursecodeID
ORDER BY f3.grade_point
Here is SQL Fiddle.
I added a table Courses with the list of all course IDs, to make the main idea of the query easier to see. Most likely you have it in the real database. If not, you can generate it on the fly from feedback by grouping by cid.
For each cid we need to find the grade. Group feedback by cid, grade to get a list of all grades for the cid. We need to pick only one grade for a cid, so we use LIMIT 1. To determine which grade to pick we order them. First, by occurrence - simple COUNT. Second, by the average score. Finally, if there are several grades than have same occurrence and same average score, then pick the grade with the smallest g_point. You can adjust the rules by tweaking the ORDER BY clause.
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
FROM courses
ORDER BY courses.cid
result set
cid CourseGrade
10 A+
11 B+
12 B
UPDATE
MySQL doesn't have lateral joins, so one possible way to get the second column g_point is to repeat the correlated sub-query. SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
FROM courses
ORDER BY CourseGPoint
result set
cid CourseGrade CourseGPoint
10 A+ 1
11 B+ 2
12 B 3
Update 2 Added average score into ORDER BY SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
,(
SELECT (AVG(workload) + AVG(easiness))/2
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS AvgScore
FROM courses
ORDER BY CourseGPoint, AvgScore DESC
result
cid CourseGrade CourseGPoint AvgScore
10 A+ 1 3.75
11 B+ 2 5
12 B 3 3
If I understood well you need an inner select to find the average, and a second outer select to find the maximum values of the average
select cid, grade, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid, grade
This solution has been tested on your data usign sql fiddle at this link
If you change the previous query to
select cid, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid
You will find the max average for each cid.
As mentioned in the comments you have to choose wich strategy use if you have more grades that meets the max average. For example if you have
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 9 | 11 | C | 1 | 3 | 6
You will have grades A+ and C soddisfing the maximum average 4.5