Getting row number based on cate (MySql) - mysql

I have the following table and data using a query
SELECT b.*, (#rownum :=#rownum +1) AS row_number
FROM notices b, (SELECT #rownum := 0 ) row
Result:
id cate rownumber
-------------------
1 5 1
2 5 2
3 6 3
4 5 4
5 5 5
6 5 6
7 5 7
I want to output the result below without using row_number() or other function since my rdbms cannot support these.
id cate rownumber
-------------------
1 5 1
2 5 2
3 6 1
4 5 3
5 5 4
6 5 5
7 5 6

To simulate ROW_NUMBER with a partition in MySQL you can simply introduce another session variable to keep track of the cate group value as you iterate over the records in notices.
SET #rn = NULL;
SET #cate = NULL;
SELECT id, cate, rn
FROM
(
SELECT
#rn:=CASE WHEN #cate = cate THEN #rn + 1 ELSE 1 END AS rn,
#cate:=cate,
id,
cate
FROM notices
ORDER BY
cate, id
) t
ORDER BY cate, rn;
Demo here:
Rextester

Related

Select limited number of rows based on unique column value

I have a table in the following format
ID SOURCE_ID
1 1
2 1
3 1
4 2
5 3
6 3
7 4
8 4
9 4
10 4
11 4
12 1
13 1
14 3
15 3
16 3
17 3
18 2
19 2
I want to be able to select 5 records MAX for each unique source_id.
So I should end up having returned 5 rows for source_id = 1, 5 rows for souce_id = 2, and so on.
Any ideas? Thank you in advance.
E.g.:
SELECT id
, source_id
FROM
( SELECT id
, source_id
, CASE WHEN #prev = source_id THEN #i:=#i+1 ELSE #i:=1 END i
, #prev := source_id prev
FROM my_table
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY source_id
, id
) x
WHERE i <=5
ORDER
BY id;

MySQL SELECT BETWEEN two points

Table places
pid pname
1 Amsterdam
2 London
3 Miami
4 Bonn
5 Oslo
6 Madrid
7 Lisbon
Table roots
id from to projectid
2 1 3 1 //Project#1 starts from Amsterdam
3 3 2 1 //Project#1 ends at London
4 3 5 2 //Project#2 starts from Miami and ends at Oslo
5 3 5 3
6 5 6 3
7 4 2 4
8 2 4 5
9 6 4 6
10 4 5 6
I need a resultset that contains all start and end points, ie:
start end projectid
1 2 1 //Amsterdam London
3 5 2 //Miami Oslo
3 6 3
4 2 4
2 4 5
6 5 6
And so, I need a list will show all projects between two cities, for example between London and Bonn:
4 2 4
2 4 5
This assume the id are in sequential order
Using variables you assign a rowid to know what is the first and the last entry of each project.
JOIN both together choose the from from F and the to from T
SQL Fiddle Demo
SELECT F.`from`, T.`to`, F.`projectid`
FROM (
SELECT `id`, `from`, `to`, `projectid`,
#row := IF(#prev = `projectid`,
#row + 1,
IF( #prev := `projectid`, 1, 1)
) as rn
FROM roots R
CROSS JOIN (SELECT #row = 0 , #prev = 0) x
ORDER BY `projectid`, `id`
) F
JOIN
(
SELECT `id`, `from`, `to`, `projectid`,
#row := IF(#prev = `projectid`,
#row + 1,
IF( #prev := `projectid`, 1, 1)
) as rn
FROM roots R
CROSS JOIN (SELECT #row = 0 , #prev = 0) x
ORDER BY `projectid`, `id` DESC -- HERE ID is DESC to get last entry
) T
ON F.`projectid` = T.`projectid`
and F.`rn` = 1
and T.`rn` = 1
OUTPUT
| from | to | projectid |
|------|----|-----------|
| 1 | 2 | 1 |
| 3 | 5 | 2 |
| 3 | 6 | 3 |
| 4 | 2 | 4 |
| 2 | 4 | 5 |
| 6 | 5 | 6 |
NOTE
Change demo query to SELECT * so you can check what is happening. Sometimes last entry equal to first entry.
For your second question depend on if you only count when city are in the first or end.
SELECT *
FROM <previous query>
WHERE (`from` = #CityA and `to`= #CityB )
OR (`from` = #CityB and `to`= #CityA )
Because if you want something considering cityes in between is much more complicated

How to calulate SUM previous and current row value in MySQL table?

My table is "Activity_table", which have 4 columns. How can I create a function, which SUM each Peroson 2 previous and current activities?
My Activity_table
ID PID AID Act
1 1 1 12
2 1 2 32
3 2 1 5
4 1 3 21
5 2 2 12
6 2 3 19
7 1 4 11
8 2 4 6
PID-PersonID; AID-ActivitieID; Act-Activitie Value
My target:
ID PID AID Act SUM
1 1 1 12 12
2 1 2 32 44
3 2 1 5 5
4 1 3 21 65
5 2 2 12 17
6 2 3 19 36
7 1 4 11 64
8 2 4 6 37
Sum1=12; Sum2=32+12; Sum3=5; Sum4=21+32+12; Sum5=12+5; Sum6=19+12+5; Sum7=11+21+32; Sum8=6+19+12; Thank you,
To use the two previous and the current row,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND ID >= a.ID - 2
AND PID = a.PID)
FROM Activity_table a;
You are taking the SUM according to the PID right? Then the last two rows of your target should be modified as,
7 1 4 11 **76**
8 2 4 6 **42**
The most flexible query is for your requirement is,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND PID = a.PID)
FROM Activity_table a;
Then if you need only the flow of SUM of a particular PID, you can change it like this,
SELECT ID,PID,AID,Act,
(SELECT SUM(Act)
FROM Activity_table
WHERE ID <= a.ID
AND PID = a.PID)
FROM Activity_table a
WHERE PID = 2;
Result:
ID PID AID Act SUM
3 2 1 5 5
5 2 2 12 17
6 2 3 19 36
8 2 4 6 42
Sorry for the previous wrong Answers (deleted).
This produces the correct answer based on your example:
SET #LastPID = 0, #Act1 = 0,#Act2 = 0,#Act3 = 0;
SELECT ID,PID,AID,Act,`SUM` FROM
(
SELECT ID,PID,AID,Act,#Act3 := IF(#LastPID != PID, 0,#Act2),#Act2 := IF(#LastPID != PID, 0,#Act1), #Act1 := Act, #Act1 + #Act2 + #Act3 `SUM`, #LastPID := PID
FROM Activity_table
ORDER BY PID,ID
) sm
ORDER BY ID
;

update statement with aggregate function

Good day everyone..!:-)
I have this table tab where totalUsed is equal to the sum of all used values referenced to name
cid name used total
1 a 1 1
2 a 3 4
3 a 6 10
4 b 3 3
5 b 7 10
6 b 10 0
7 a 5 0
i have this code but it only copy totalUsed's adjacent used value
UPDATE tab
SET totalUsed=
(
SELECT SUM(used)
)
cid name used total
1 a 1 1
2 a 3 3
3 a 6 6
4 b 3 3
5 b 7 7
6 b 10 10
7 a 5 5
if used is set as 10 for cid 6, totalUsed should be 20
and for cid 7 it should be 15.
how to do it in mysql?
it should look like this.
cid name used total
1 a 1 1
2 a 3 4
3 a 6 10
4 b 3 3
5 b 7 10
6 b 10 20
7 a 5 15
thanks for help
:-)
In most dialects of SQL, you can do this using an update with a correlated subquery:
UPDATE tab
SET totalUsed = (SELECT SUM(used)
from tab tab2
where tab2.name = tab.name and
tab2.cid <= tab.cid
);
EDIT:
The above will not work in MySQL. You can do this instead:
UPDATE tab join
(select tab2.cid,
(SELECT SUM(used)
from tab tab3
where tab3.name = tab2.name and
tab3.cid <= tab2.cid
) as cum_used
from tab tab2
) tab2
on tab.cid = tab2.cid
SET tab.totalUsed = tab2.cum_used;

how to retrieve hierarchical data retrieved as a collection

I have implemented the following hierarchical data using MySQL
1
|----- 2
|----- 3
4
|----- 5
|----- 6
|----- 7
id | path | level | parent_id | content |
-------------------------------------------------------------------
1 1 1 NULL xxx
2 1:2 2 1 yyy
3 1:3 2 1 abc
4 4 1 NULL zzz
5 4:5 2 4 yyy
6 4:6 2 4 abc
7 4:6:7 3 6 abc
Assuming I have only these records,
how do I retrieve them in a tree structure and yet within a single collection starting with the last tree?
What I expected from the query or stored procedure is to return me the following in exactly this order
id
-----
4
5
6
7
1
2
3
How do I do the same but starting with the first tree?
id
-----
1
2
3
4
5
6
7
try including order by desc
ORDER by path desc,id asc
To cope with parents / children possibly something like this:-
SELECT PathTable.*, SUM(OrderVal) AS OrderCalc
FROM
(
SELECT id,
POW(100, MaxDepth-i-1) * SUBSTRING_INDEX(SUBSTRING_INDEX(path, ':', (i+1)), ':', -1) AS OrderVal
FROM PathTable
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Sub1
CROSS JOIN (SELECT MAX(LENGTH(path) - LENGTH(REPLACE(path, ':', ''))) + 1 AS MaxDepth FROM PathTable) Sub2
WHERE i <= (LENGTH(path) - LENGTH(REPLACE(path, ':', '')))
) Sub1
INNER JOIN PathTable
ON Sub1.id = PathTable.id
GROUP BY PathTable.id
ORDER BY OrderCalc
This is splitting up the path field and calculating an order value based on 100 to the power of the level of the bit of path, taking into account the max number of bits of path, times that bit of path (so 4:6:7 lands up as 7 + 6 * 100^1 + 4 * 100^2), then ordering by that.
100 chosen just as it is bigger than the largest single value in the path.