Mysql query configuration - mysql

I have this query and runs perfectly, i just want to short the results to help me for quick reading :
SELECT numbers
FROM vista
WHERE id IN (
SELECT b.id + 3 FROM(
SELECT t1.id, t1.numbers t1val, t2.numbers t2val
FROM vista t1
JOIN vista t2 ON t1.id = t2.id-1
JOIN vista t3 ON t1.id = t3.id-2
WHERE t1.id = (SELECT MAX(id) - 2 FROM vista)
) a
JOIN (
SELECT t1.id, t1.numbers t1val, t2.numbers t2val, t3.numbers t3val
FROM vista t1
JOIN vista t2 ON t1.id = t2.id-1
JOIN vista t3 ON t1.id = t3.id-2
WHERE t1.id < (SELECT MAX(id) - 2 FROM vista)
) b
ON a.t1val = b.t1val
AND a.t2val = b.t2val
AND a.t3val = b.t3val
AND a.id <> b.id
)
ORDER BY id;
And the results it is like :
3
5
2
7
5
5
7
3
How can i get results counted in group and percentage :
Like :
5 = 3 (37.50%)
7 = 2 (25.00%)
3 = 2 (25.00%)
2 = 1 (12.50%)

Well if your query works than you should do something like this to achieve result you want:
Solution one - this will give you numbers, countend numbers in group and percentage in seperate column...
SELECT numbers, COUNT(numbers), (COUNT(numbers) / (SELECT COUNT(numbers)
FROM vista
/*your WHERE clause*/)) * 100 AS percent
FROM vista
-- your WHERE Statement
GROUP BY numbers
-- your ORDER BY
Here is a sql fiddle to see how that's look like http://sqlfiddle.com/#!9/08b4e/3
Solution two - this will give you numbers in one column and counted numbers in group and percentage in other:
SELECT numbers, CONCAT(CountNum, ' (', percent, '%)') AS counted
FROM (SELECT numbers, COUNT(numbers) AS CountNum, (COUNT(numbers) / (SELECT COUNT(numbers)
FROM vista
WHERE ID BETWEEN 1 AND 8
/*your WHERE clause*/)) * 100 AS percent
FROM vista
WHERE ID BETWEEN 1 AND 8
-- your WHERE clause this is just for a testing purpose
GROUP BY numbers
ORDER BY ID) AS srcTable
-- your ORDER BY clause this is just for a testing purpose
Here is Fiddle for that http://sqlfiddle.com/#!9/51275/1
Of course you need to insert your WHERE clause instead of mine i just put this one to test it. GL i hope i help a little.

Related

Sort records based on string

Please consider the table below
Id F1 F2
---------------------------
1 Nima a
2 Eli a
3 Arian a
4 Ava b
5 Arsha b
6 Rozhan c
7 Zhina c
I want to display records by sorting COLUMN F2 to display one record from each string category (a,b,c) in order
Id F1 F2
---------------------------
1 Nima a
5 Arsha b
6 Rozhan c
2 Eli a
4 Ava b
7 Zhina c
3 Arian a
NOTE: a,b,c could be anything... it should take one record from one entry and then 2nd from 2nd entry.
I have used join, or group by records but no success.
MySQL version 5.7 – Syed Saqlain
SELECT id, f1, f2
FROM ( SELECT t1.id, t1.f1, t1.f2, COUNT(*) cnt
FROM test t1
JOIN test t2 ON t1.f2 = t2.f2 AND t1.id >= t2.id
GROUP BY t1.id, t1.f1, t1.f2 ) t3
ORDER BY cnt, f2;
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=8138bd9ab5be36ba534a258d20b2e555
ROW_NUMBER() alternative for lower version of MYSQL. This query will work for version 5.5, 5.6 & 5.7.
-- MySQL (v5.7)
SELECT t.id, t.f1, t.f2
FROM (SELECT #row_no:=CASE WHEN #db_names=d.f2 THEN #row_no+1 ELSE 1 END AS row_number
, #db_names:= d.f2
, d.f2
, d.f1
, d.id
FROM test d,
(SELECT #row_no := 0,#db_names:='') x
ORDER BY d.f2) t
ORDER BY t.row_number, t.f2
Please check from url https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=02dbb0086a6dd7c926d55a690bffbd06
You can use window functions in the order by:
select t.*
from t
order by row_number() over (partition by f2 order by id),
f2;
The row_number() function (as used above) assigns a sequential number starting with 1 to each value of f2.
In older versions of MySQL, you can use a correlated subquery instead:
order by (select count(*) from t t2 where t2.f2 = t.f2 and t2.id <= t.id),
f2;
For performance, you want an index on (f2, id).

Condensing MySQL ordered group values

This question is an extension of mysql compress order_by values.
My table has groups of ordered numbers, with undesired gaps. How can I renumber each of these groups, while keeping the original order?
Group Order Desired Order
A 1 1
A 3 2
A 6 3
A 7 4
B 2 1
B 3 2
B 8 3
C 1 1
C 7 2
C 8 3
You can also get the desired order by using a correlated sub query without using and variables
select t1.*,
(
select count(*)
from demo t2
where t1.`group` = t2.`group`
and t1.`order` > t2.`order`
) + 1 desiredorder
from demo t1
DEMO
Or to update same table with your desired order you can use below query
update demo a
join (select t1.*,(
select count(*)
from demo t2
where t1.`group` = t2.`group`
and t1.`order` > t2.`order`
) + 1 desiredorder
from demo t1
) b on a.`group` = b.`group`
and a.`order` = b.`order`
set a.`order` = b.desiredorder
DEMO
Note make sure to add an index on group and order column for better performance.
You can create a variable to store the previous value of group and another one for the desiredorder. Essentially this is a mimic of a Window Function ROW_NUMBER which MySql doesn't support.
I renamed the columns as group=col1, order=col2
select col1,
col2,
neworder
from (
select t.col1,
t.col2,
case when #prev=t.col1 then #id:=#id+1 else #id:=1 end as neworder,
#prev:=t.col1
from (select #prev:=null, #id:=0) a,
toorder t
order by t.col1
) a
See it working here: http://sqlfiddle.com/#!9/9d8528/2
The external query is only needed if you want to pull out only those three columns.

find 4 consecutive rows with a specific value using a mysql query

My table has 4 columns: id (autoincrement), machine (integer between 1 and 300), event (integer), status (string)
I need to run a query on this table, that returns the four machines with the lowest possible machine number where event="5" and status = "free" and that are consecutive numbers.
for example if machine 3 is busy, the query should NOT return 1,2,4,5 because they are not consequent. instead if machines 4,5,6,7 are free it should return those. It should NOT return 5,6,7,8 since it is not the lowest possible machinenumber. the lowest possible is 4,5,6,7.
select * from mytable where event="5" and status="free" order by machine asc limit 4
does exactly what i need, except that it does return all rows, not taking into account that they MUST be consequent in the machines column.
Can this be done?
sample data as requested:
id - machine - event - status
22 1 5 free
23 2 5 free
24 3 5 busy
25 4 5 busy
26 5 5 free *
27 6 5 free *
28 7 5 free *
29 8 5 free *
30 9 5 free
31 10 5 busy
32 11 5 free
The lines marked with * are the lines i would need to get. the first 4 consecutive rows on column machine, with status value free and event id = 5.
Something like this should work
SELECT SUBSTRING_INDEX(GROUP_CONCAT(machine ORDER BY machine),',',4) as machines FROM
(SELECT machine,
CASE WHEN machine=#machine + 1 THEN #n ELSE #n:=#n+1 END AS g,
#machine := machine As m
FROM
t, (SELECT #n:=0) r, (SELECT #machine := '') z
WHERE event=5 and status="free"
ORDER BY
id) sub
GROUP BY g
HAVING COUNT(*) >=4
If you want ALL the rows
SELECT t.id,t.machine,t.event,t.status FROM
(SELECT id,machine,event,status,GROUP_CONCAT(id ORDER BY id) gr FROM
(SELECT *,
CASE WHEN machine=#machine + 1 THEN #n ELSE #n:=#n+1 END AS g,
#machine := machine As m
FROM
t, (SELECT #n:=0) r, (SELECT #machine := '') z
WHERE event=5 and status="free"
ORDER BY
id) sub
GROUP BY g
HAVING COUNT(*) >=4) o
JOIN t ON FIND_IN_SET(t.id,gr)
ORDER BY id LIMIT 4
Test
Test2
If I understand correctly, this should do the trick
select t1.id, t2.id, t3.id, t4.id
from (select * from mytable where event="5" and status="free") t1
join (select * from mytable where event="5" and status="free") t2
on t1.id + 1 = t2.id
join (select * from mytable where event="5" and status="free") t3
on t1.id + 2 = t3.id
join (select * from mytable where event="5" and status="free") t4
on t1.id + 3 = t4.id
order by t1.id
limit 1
May require some tweaking on the join conditions (hard to tell without examples).
this depends a little on the size of your dataset, but for small datasets this should work:
select * from mytable m1 where m1.event="5" and m1.status="free"
and(m1.machine-1 in (select machine from mytable where event="5" and status="free")
and m1.machine-2 in (select machine from mytable where event="5" and status="free")
and m1.machine-3 in (select machine from mytable where event="5" and status="free")
OR( m1.machine+1 in (select machine from mytable where event="5" and status="free")
and m1.machine+2 in (select machine from mytable where event="5" and status="free")
and m1.machine+3 in (select machine from mytable where event="5" and status="free") )
order by m1.machine asc limit 4
for larger datasets, you'll want to use a JOIN to accomplish the same.
you can also just use the second half to find the first instance and then start your query from there.

How can I add subtotal to table in MySQL?

Assume my table looks like the following:
id count sub_total
1 10 NULL
2 15 NULL
3 10 NULL
4 25 NULL
How can I update this table to look like the following?
id count sub_total
1 10 10
2 15 25
3 10 35
4 25 60
I can do this easy enough in the application layer. But I'd like to learn how to do it in MySQL. I've been trying lots of variations using SUM(CASE WHEN... and other groupings to no avail.
If your id field is sequential and growing then a correlated subquery is one way:
select *, (select sum(count) from t where t.id <= t1.id)
from t t1
or as a join:
select t1.id, t1.count, sum(t2.count)
from t t1
join t t2 on t2.id <= t1.id
group by t1.id, t1.count
order by t1.id
To update your table (assuming the column sub_total already exists):
update t
join (
select t1.id, sum(t2.count) st
from t t1
join t t2 on t2.id <= t1.id
group by t1.id
) t3 on t.id = t3.id
set t.sub_total = t3.st;
Sample SQL Fiddle showing the update.

Mysql query random order (pause and continue) question

Okay i am trying to create a mysql query that does this:
show 3 random records from table then after the 3th record show TEXT
and then show the same 3 items but other field (equaling to the items ofcourse) from same table.
eg table info:
--ids | titles------
10 | one
20 | two
30 | three
and the query results from the given example:
30 10 20 TEXT three one two
if anyone understand what i am asking,post your suggestion/asnwer
thanks for your time all :)
Just for kicks..
select t1.id, t2.id, t3.id, 'TEXT', t1.title, t2.title, t3.title
FROM
(
select #r := #r + 1 rownum, id
from (select #r:=0) initvar, (
select id
from tbl
order by rand()
limit 3
) X
) Y
join tbl t1 on Y.rownum=1 and t1.id = Y.id
join tbl t2 on Y.rownum=2 and t2.id = Y.id
join tbl t3 on Y.rownum=3 and t3.id = Y.id
You should really just do the query below, and do whatever display processing using the 3 rows returned, in whatever programming environment you use (Java/PHP/.Net etc).
select id, title
from tbl
order by rand()
limit 3
EDIT
To get the data in 7 different rows, you can use the below. I stress again that this is front-end display code. I will not use such SQL code in a production system.
select display
from
(
select sorter, rownum,
case when sorter=3 then title else id end display
from
(
select #r := #r + 1 rownum, id, title
from (select #r:=0) initvar,
(
select id, title
from tbl
order by rand()
limit 3
) X
) Y, (select 1 sorter union all select 3) dup
union all
select 2, 0, 'TEXT'
) Z
order by sorter, rownum
Example Output
7
2
1
TEXT
test 7 << title for id=7
test 2
test 1