Mysql sort data alternatively - mysql

I have a big table where data are structured like this
My table car
id_car | Site_car | descr_car
-----------------------------------
1 | onesite | onedesc
2 | twosite | twodesc
3 | twosite | onedesc
4 | onesite | onedesc
5 | twosite | twodesc
6 | onesite | onedesc
7 | treesite | onedesc
8 | treesite | onedesc
I want to be able to display the column site_car randomly but with onesite first twosite second and threesite third each 15 time or more
what I want to display
id_car | Site_car | descr_car
-----------------------------------
4 | onesite | onedesc
3 | twosite | twodesc
7 | treesite | onedesc
1 | onesite | onedesc
2 | twosite | twodesc
6 | treesite | onedesc
Do you guys have idea?
Thx

This is tricky in MySQL. The idea is to enumerate the rows and then order by that enumeration:
select c.*
from (select c.*,
(#rn := if(#sc = site_car, #rn + 1,
if(#sc := site_car, 1, 1)
)
) as rn
from (select c.*
from car c
order by site_car, id_car
) c cross join
(select #sc := -1, #rn := 0) params
) c
order by rn, field(site_car, 'onesite', 'twosite', 'threesite');
By the way this is much simpler in MySQL 8+:
select c.*
from car c
order by row_number() over (partition by site_car order by id_car),
field(site_car, 'onesite', 'twosite', 'threesite');

you can try this
SET #Fno:= 999
SET #Sno:= 9999
SET #Tno:= 99999
SELECT id_car, Site_car , descr_car from
(SELECT
#row_number:=CASE
WHEN Site_car = 'onesite' THEN #Fno + 1
WHEN Site_car = 'twosite' THEN #Sno + 1
ELSE #Tno+1
END AS num,* from car) order by num

Related

SQL partition by with original order

Here's the original MySQL table:
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
When I use select Id, Num, row_number() over(partition by Num) from t, MySQL automatically disrupts the order of the Num column. However, I want to keep Num column order unchanged.
Specifically, the ideal output should be like:
+----+-----+-----+
| Id | Num | row |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 1 | 1 |
| 6 | 2 | 1 |
| 7 | 2 | 2 |
+----+-----+-----+
How to write this MySQL query?
This is a gaps-and-islands problem. I would recommend using the difference between row numbers to identify the groups.
If id is always incrementing without gaps:
select id, num,
row_number() over(partition by num, id - rn order by id) rn
from (
select t.*, row_number() over(partition by num order by id) rn
from mytable t
) t
order by id
Otherwise, we can generate our own incrementing id with another row_number():
select id, num,
row_number() over(partition by num, rn1 - rn2 order by id) rn
from (
select t.*,
row_number() over(order by id) rn1,
row_number() over(partition by num order by id) rn2
from mytable t
) t
order by id
Demo on DB Fiddle - for your sample data, both queries yield:
id | num | rn
-: | --: | -:
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 1 | 1
6 | 2 | 1
7 | 2 | 2
You can do this by writing your own row_number to have greater control over its partitioning.
set #prev_num = null;
set #row_number = 0;
select
id,
-- Reset row_number to 1 whenever num changes, else increment it.
#row_number := case
when #prev_num = num then
#row_number + 1
else
1
end as `row_number`,
-- Emulate lag(). This must come after the row_number.
#prev_num := num as num
from foo
order by id;
Same idea as the solution proposed by Schwern. Just another style of syntax in MySQL which I find very simplistic and easy to use.
Select
id
, num
, value
from
(select
T.id,
T.num,
if( #lastnum = T.num, #Value := #Value + 1,#Value := 1) as Value,
#lastnum := T.num as num2
from
mytable T,
( select #lastnum := 0,
#Value := 1 ) SQLVars
order by
T.id) T;
DB fiddle link - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=e04692841d091ccd54ee3435a409c67a

Mysql Select and count rows with multiple same values

I am trying to create a query that allows me to select the data like shown below
id Counter_Type Champion_Name Counter_Lane
---|------------|------------|--------------
1 | 1 | Ahri | 1
2 | 1 | Ahri | 2
5 | 1 | Ahri | 2
3 | 1 | Ahri | 3
4 | 1 | Ahri | 2
6 | 1 | Teemo | 1
7 | 1 | Warwick | 4
8 | 1 | Warwick | 4
It should count the Counter_Lane and then the Counter_Type with the most should be shown for that name as shown below how it should show the data:
id Counter_Type Champion_Name Counter_Lane
---|------------|------------|--------------
1 | 1 | Ahri | 2
2 | 1 | Teemo | 1
3 | 1 | Warwick | 4
I have tried the following code and its the closest I have came for over 3 hours now, so could someone help please.
SELECT
a.Counter_Type, Champion_For, a.Counter_Lane, a.Champion_Name, COUNT(*) as Amount, sum(vote_type = 'up') as Upvotes, sum(vote_type = 'down') as Downvotes, sum(vote_type = 'up')-sum(vote_type = 'down') as Totalvotes
FROM Champion_Counters_Data a
JOIN ( SELECT c.Counter_Lane, c.Champion_Name, COUNT(*) magnitude
FROM Champion_Counters_Data c
WHERE
Champion_For = "Aatrox" AND Counter_Type = 1 GROUP BY Champion_Name, Counter_Lane ORDER BY magnitude) b ON a.Champion_Name = b.Champion_Name AND b.Counter_Lane = a.Counter_Lane
GROUP BY Champion_Name
SELECT * FROM your_table GROUP BY MAX(Counter_Lane)
This query is based on the output you want from the table you have given.
You will need many subqueries as MySQL doesn't allow windows function or CTE.
Rextester Demo
SELECT #rn := #rn + 1 as id,
t3.*
from
(select t1.*
FROM
(SELECT counter_type,
champion_name,
counter_lane,
count(*) AS cnt
FROM table53
GROUP BY champion_name,
counter_lane
) t1
INNER JOIN
(SELECT counter_type,
champion_name,
max(cnt) AS mcnt
FROM
(SELECT counter_type,
champion_name,
counter_lane,
count(*) AS cnt
FROM table53
GROUP BY champion_name,
counter_lane
) t
GROUP BY counter_type,
champion_name
) t2
ON t1.counter_type=t2.counter_type
AND t1.champion_name=t2.champion_name
AND t1.cnt=t2.mcnt
) t3
,(SELECT #rn := 0) t
;
Output
+-----+--------------+---------------+--------------+-----+
| id | counter_type | champion_name | counter_lane | cnt |
+-----+--------------+---------------+--------------+-----+
| 1 | 1 | Ahri | 2 | 3 |
| 2 | 1 | Teemo | 1 | 1 |
| 3 | 1 | Warwick | 4 | 2 |
+-----+--------------+---------------+--------------+-----+
Idea is to first group by champion_name and counter_lane and get the count . So for Ahri you will get cnt as 3. Now use another subquery to get corresponding counter_lane, which will be 2 for Ahri. At last, use a sequence number to generate id as 1,2,3 etc.
Try following SQL statement:
SELECT Counter_Type , Champion_Name, MAX(Counter_Lane) 'Counter_Lane'
FROM(
SELECT Counter_Type , Champion_Name , Counter_Lane
FROM Champion_Counters_Data
GROUP BY Counter_Type , Champion_Name
HAVING COUNT(Counter_Lane) >= 2
) tb
GROUP BY Counter_Type , Champion_Name

cumulative product over a big MySQL table

I have a big MySQL table on which I'd like to calculate a cumulative product. This product has to be calculated for each group, a group is defined by the value of the first column.
For example :
name | number | cumul | order
-----------------------------
a | 1 | 1 | 1
a | 2 | 2 | 2
a | 1 | 2 | 3
a | 4 | 8 | 4
b | 1 | 1 | 1
b | 1 | 1 | 2
b | 2 | 2 | 3
b | 1 | 2 | 4
I've seen this solution but don't think it would be efficient to join or subselect in my case.
I've seen this solution which is what I want except it does not partition by name.
This is similar to a cumulative sum:
select t.*,
(#p := if(#n = name, #p * number,
if(#n := name, number, number)
)
) as cumul
from t cross join
(select #n := '', #p := 1) params
order by name, `order`;

Group, count and concat laps

I can't resolve this problem (race), I need show the time for each LAP. This is times table
id | race_id | car_num | time |
+-----+-------------+---------+------------+
1 | 8 | 25 | 00:09:05 |
2 | 8 | 33 | 00:09:35 |
3 | 8 | 10 | 00:09:55 |
4 | 8 | 25 | 00:18:15 |
5 | 8 | 33 | 00:19:05 |
6 | 8 | 25 | 00:39:45 |
I tried this query:
SELECT
car_num, COUNT(car_num) as laps, race_id, concat(vlap,'-',time) as times
FROM
(SELECT num_car, concat(time,'-',v1) vlap
FROM tiempos) vti
GROUP BY
car_num
This is output required:
car_num | laps | race_id | times |
+-----+-------------+---------+------------------------------------------------+
25 | 3 | 8 | lap1 00:09:05, lap2 00:18:15, lap3 00:39:45 |
33 | 2 | 8 | lap1 00:09:35, lap2 00:19:05 |
10 | 1 | 8 | lap1 00:09:55 |
I'm dizzy, some idea please
You can get most of what you want with a simple group_concat():
select car_num, count(*) as laps, race_id, group_concat(time order by id separator ', ' ) as times
from tiempos t
group by car_num, race_id;
If you need the lap number, you can get that using variables:
select car_num, count(*) as laps, race_id, group_concat('lap', rn, ' ', time order by id separator ', ' ) as times
from (select t.*,
(#rn := if(#t = time, #rn + 1,
if(#t := time, 1, 1)
) as rn
from tiempos t cross join
(select #rn := 0, #t := '') vars
order by race_id, car_num, time
) t
group by car_num, race_id;

Limiting the output of specific column sql hana

I have a table structure as given below and what I'd like to be able to do is retrieve the top three records with the highest value for each Company code.
I've googled and I couldn't find a better way so hopefully you guys can help me out.
By the way, I'm attempting this in MySQL and SAP HANA. But I am hoping that I can grab the "structure" if the query for HANA if I can get help for only MySQL
Thanks much!
Here's the table:
http://pastebin.com/xgzCgpKL
In MySQL you can do
To get exactly three records per group (company) no matter ties emulating ROW_NUMBER() analytic function. Records with the same value get the same rank.
SELECT company, plant, value
FROM
(
SELECT company, plant, value, #n := IF(#g = company, #n + 1, 1) rnum, #g := company
FROM table1 CROSS JOIN (SELECT #n := 0, #g := NULL) i
ORDER BY company, value DESC, plant
) q
WHERE rnum <= 3;
Output:
| COMPANY | PLANT | VALUE |
|---------|-------|-------|
| 1 | C | 5 |
| 1 | B | 4 |
| 1 | A | 3 |
| 2 | G | 6 |
| 2 | C | 5 |
| 2 | D | 3 |
| 3 | E | 8 |
| 3 | A | 7 |
| 3 | B | 3 |
Get all records per group that have a rank from 1 to 3 emulating DENSE_RANK() analytic function
SELECT company, plant, value
FROM
(
SELECT company, plant, value, #n := IF(#g = company, IF(#v = value, #n, #n + 1), 1) rnum, #g := company, #v := value
FROM table1 CROSS JOIN (SELECT #n := 0, #g := NULL, #v := NULL) i
ORDER BY company, value DESC, plant
) q
WHERE rnum <= 3;
Output:
| COMPANY | PLANT | VALUE |
|---------|-------|-------|
| 1 | C | 5 |
| 1 | B | 4 |
| 1 | A | 3 |
| 1 | E | 3 |
| 1 | G | 3 |
| 2 | G | 6 |
| 2 | C | 5 |
| 2 | D | 3 |
| 3 | E | 8 |
| 3 | A | 7 |
| 3 | B | 3 |
| 3 | G | 3 |
Here is SQLFiddle demo
UPDATE: Now it looks like HANA supports analytic functions so the queries will look like
SELECT company, plant, value
FROM
(
SELECT company, plant, value,
ROW_NUMBER() OVER (PARTITION BY company ORDER BY value DESC) rnum
FROM table1
)
WHERE rnum <= 3;
SELECT company, plant, value
FROM
(
SELECT company, plant, value,
DENSE_RANK() OVER (PARTITION BY company ORDER BY value DESC) rank
FROM table1
)
WHERE rank <= 3;
Here is SQLFiddle demo It's for Oracle but I believe it will work for HANA too