MySQL using variables in SELECT subquery - mysql

Is it possible to use variables in SELECT without SET before it?
Somehow '#period' variable not always works properly. For example in MySQL Workbench (v5.2), the result is showed only after 2nd invocation, if the variable is changed the result will be correct only on 2nd run. phpMyAdmin shows correct rows count but no entries, can someone explain please what is wrong in using variables in such a way:
select sql_no_cache #num := #num + 1 as `#`, l.* from (
select s.* from (
select
#num := 0 as 'Label 1',
#period := 31 as 'LAbel 2',
'' as 'Label 3'
union
select concat(users.first_name, ' ',users.last_name),u.type, u.date, u.description from (
select c.user_id as uguid, 'type1' as type, c.date_start as date, c.description from table1 c
where deleted = 0
and date_start > SUBDATE(CURRENT_DATE,#period)
union
...
) as u) as l

Found a mistake.
The reason is that the variable is used before it's definition. '#period' is defined in the query, but it's first usage occures in the subquery that's executes first.
So the solution is to put variable definition on the same level with the subquery where it used.
Something like:
select sql_no_cache #num := #num + 1 as `#`, l.* from (
select s.* from (
select
#num := 0 as 'Label 1',
'' as 'LAbel 2',
'' as 'Label 3'
union
select concat(users.first_name, ' ',users.last_name),u.type, u.date, u.description from (
select o2.* from
(select #period:=31) as o1
join (
select c.user_id as uguid, 'type1' as type, c.date_start as date, c.description from table1 c
where deleted = 0
and date_start > SUBDATE(CURRENT_DATE,#period)
union
...
) as o2
) as u
) as l

Related

Mysql query get SUM() specific row?

Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d

MySQL - Parallel merge two unrelated queries with same # of rows

I have two tables:
exam_outline_items:
jml_quiz_pool:
Of all the things I've tried, this got me the closest:
select t1.sequence, t1.title, t2.q_cat, t2.q_count
from student_pl.exam_outline_items t1
cross join pe_joomla.jml_quiz_pool t2
where t1.exam_outline_id = 5 and t1.chapter_num > 0
and t2.q_id = 1109 and t2.q_count > 0
group by title
Which produces this result:
I just need those q_cat values to be different, like they are in the 2nd query.
Thanks in advance for your help.
You have to have something to connect them with. If you don't have such a column, you can simulate one by creating a rownumber with variables.
select sequence, title, q_cat, q_count from (
select t1.sequence, t1.title, #r1 := #r1 + 1 as rownumber
from student_pl.exam_outline_items t1
, (select #r1 := 0) var_init
where t1.exam_outline_id = 5 and t1.chapter_num > 0
order by t1.sequence
) a
inner join
(
select t2.q_cat, t2.q_count, #r2 := #r2 + 1 as rownumber
from pe_joomla.jml_quiz_pool t2
, (select #r2 := 0) var_init
where t2.q_id = 1109 and t2.q_count > 0
order by t2.q_cat
) b on a.rownumber = b.rownumber;
Also note, that I used order by in those queries. In a database you have no sort order unless you explicitly set it with order by.

MySQL Simple row num incremental counter

I'm trying to produce an incremental counter (column 'rownum' in the query below) in an SQL select clause. the counter should start over each time a new user switches.
SELECT * FROM (
SELECT CONCAT(' ',g.node1,' ',g.node2),
#r:= CASE WHEN #g = g.`user` THEN #r +1 ELSE 1 END rownum,
#g:= g.`user` user_group
FROM sn.sn_graph_reduced g
CROSS JOIN (SELECT #g:=0,#r:=0) t2
ORDER BY `user` , RAND()
) t
WHERE rownum <= 100
However, the above code snippet returns the row number, and since the records are RANDOMLY sampled, the row numbers are not incremental.
What I need is a simple counter (1,2,3....) for each row returned.
thanks
Try putting the variable outside of the inline view:
SELECT t.*,
#r:= CASE WHEN #t = t.`user` THEN #r +1 ELSE 1 END rownum,
#t:= t.`user` user_group
FROM (
SELECT CONCAT(' ',g.node1,' ',g.node2), g.`user`
FROM sn.sn_graph_reduced g
ORDER BY `user` , RAND()
) t
CROSS JOIN (SELECT #t:=0,#r:=0) t2
where rownum <= 100
the method for incrementing row number doesn't cope with RAND() directly, so use values from rand() as a column. Also initiate #g as '' not zero and then you need a final ORDER BY.
SELECT
*
FROM (
SELECT
CONCAT(' ', g.node1, ' ', g.node2) AS node_concat
, #r:= IF(#g = g.`user`, #r + 1, 1) AS rownum
, #g:= g.`user` AS user_group
FROM (
SELECT *, rand() AS R FROM sn_graph_reduced
) g
CROSS JOIN ( SELECT #g:= '' ,#r:= 1 ) t2
ORDER BY
`user`
, R
) t
WHERE rownum <= 100
ORDER BY
user_group
, rownum
;
see: This SQLfiddle

select every other row in MySQL without depending on any ID?

Considering following table that doesn't have any primary key, can I select every other row?
col1 col2
2 a
1 b
3 c
12 g
first select must find: 2, 3
second select must find: 1, 12
is that possible?
In unique MySQL fashion:
select *
from (
select *
, #rn := #rn + 1 as rn
from Table1
join (select #rn := 0) i
) s
where rn mod 2 = 0 -- Use = 1 for the other set
Example at SQL Fiddle.
Try this. I've adapted it from the answer linked below.
I tested it on SQLFiddle and it appears to work.
http://sqlfiddle.com/#!2/0bccf/28
http://sqlfiddle.com/#!2/0bccf/29
Odd Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 1
Even Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 0
Adapted from:
MySQL row number
yes possible using temp variable
Example :
set #a := 0;
select * from car_m_city WHERE mod((#a:=#a+1), 2) = 1
Explanation :
here in sql we declare #a( set #a := 0;) temp variable.(#a:=#a+1) now #a increment by 1.jsut like simple way to check odd or even
mod((#a:=#a+1), 2) = 1 for odd data
mod((#a:=#a+1), 2) = 0 for even data
This works for me.
SET #row_number = 0;
select* from (
SELECT
(#row_number:=#row_number + 1) AS num, col1,col2
FROM
TABLE1
) as t WHERE num%2=0
You can use mod 1 for odd or mod 0 for even rows
This should work for MySQL:
SELECT col1, col2
FROM (
SELECT col1, col2, #rowNumber:=#rowNumber+ 1 rn
FROM YourTable
JOIN (SELECT #rowNumber:= 0) r
) t
WHERE rn % 2 = 1
This uses % which is the MOD operator.
And here is the sample fiddle: http://sqlfiddle.com/#!2/cd31b/2

Order By Issue with MySQL vs SQL Server

I have one SQL query in SQL Server like this
SELECT
CASE WHEN ROW_NUMBER() OVER(PARTITION BY _no ORDER BY _no asc) = 1 THEN
_no ELSE '' END
as row_no,
_no,
_name,
r._names
FROM
(
SELECT '1' as _no, 'vikas' as _name UNION ALL
SELECT '1', 'kratika' UNION ALL
SELECT '2', 'vikas' UNION ALL
SELECT '1', 'kratika kastwar'
) t
INNER JOIN
(
SELECT '1' as _nos, 'One' as _names UNION ALL
SELECT '2', 'two'
) r
ON r._nos = t._no
ORDER BY _no
Output:
row_no _no _name _names
------ ---- --------------- ------
1 1 kratika One
1 kratika kastwar One
1 vikas One
2 2 vikas two
And the same I am doing in MySQL like this
SELECT
CASE WHEN _no = #i THEN '' ELSE #i := _no END
as row_no,
_no,
_name,
r._names
FROM
(
SELECT '1' as _no, 'vikas' as _name UNION ALL
SELECT '1', 'kratika' UNION ALL
SELECT '2', 'vikas' UNION ALL
SELECT '1', 'kratika kastwar'
) t
INNER JOIN
(
SELECT '1' as _nos, 'One' as _names UNION ALL
SELECT '2', 'two'
) r
ON r._nos = t._no
,
(SELECT #i := '') temp
ORDER BY _no
Output :
1 1 vikas One
1 kratika One
1 1 kratika kastwar One
2 2 vikas two
But I am expecting output in MySQL like this
1 1 kratika One
1 kratika kastwar One
1 vikas One
2 2 vikas two
I don't want to use query like this in MySQL as desc here MYSQL Order By W/Count
SELECT
CASE WHEN _no = #i THEN '' ELSE #i := _no END
as row_no,
_no,
_name,
_names
FROM
(SELECT
*
FROM
(
SELECT '1' as _no, 'vikas' as _name UNION ALL
SELECT '1', 'kratika' UNION ALL
SELECT '2', 'vikas' UNION ALL
SELECT '1', 'kratika kastwar'
) t
INNER JOIN
(
SELECT '1' as _nos, 'One' as _names UNION ALL
SELECT '2', 'two'
) r
ON r._nos = t._no
,
(SELECT #i := '') temp
ORDER BY _no) t
How I can achieve the same in MySQL, query performance is major parameter
I think what's happening here is that MySQL is constructing the resultset and then going through an extra step to order it according to the ORDER BY clause. Since the 'kratika kastwar' row comes after the row where _no is 2, you get the unexpected output.
The solution, I guess, would be to put the basic SELECT (without the special user-variable shenanigans) in a subquery in the FROM clause, applying the ORDER BY clause to the subquery. Then do the user-variable work in the outer query. That way the ordering has already happened.
Edit: I see that you said you don't want to do this. I don't think you have a choice, unless you can find a way to get MySQL to not do the ORDER BY by performing a filesort step on the computed results (very unlikely).
SELECT
CASE WHEN _no = #i THEN '' ELSE #i := _no END
as row_no,
_no,
_name,
_names
FROM
(SELECT
*
FROM
(
SELECT '1' as _no, 'vikas' as _name UNION ALL
SELECT '1', 'kratika' UNION ALL
SELECT '2', 'vikas' UNION ALL
SELECT '1', 'kratika kastwar'
) t
INNER JOIN
(
SELECT '1' as _nos, 'One' as _names UNION ALL
SELECT '2', 'two'
) r
ON r._nos = t._no
,
(SELECT #i := '')