how we use assigment operator (:=) in procedure without cursor - mysql

i have this query (without procedure)
SELECT row_number,current_product_id,prev_product_id FROM
(
SELECT
#row_num:=#row_num+1 AS row_number,
#pr_product_id AS prev_product_id,
kd_barang AS current_product_id,
#pr_product_id:=kd_barang
FROM m_barang
CROSS JOIN ( SELECT #row_num :=0 AS row_num) rn
CROSS JOIN ( SELECT #pr_product_id :='' AS row_num) prev_product_id
) data
LIMIT 5;
with output
i want to change it into procedure with same output without using cursor , how it will be? thank you

Related

how to cast input in "SELECT * FROM PRODUCT LIMIT CAST(select CAST('1' AS UNSIGNED)), 5"?

select * from product limit (select CAST('1' AS UNSIGNED)) ,5;
this will give error for syntax
also tried create view to replace the (select CAST('1' AS UNSIGNED)), which still doesnt work
I am using mysql.
LIMIT clause cannot take expressions or variables. Therefore if you absolutely need such functionality, you must do a huge workaround - you have to simulate it. Here is one variant:
SELECT t1.*
FROM(
SELECT product.*, #rownum:=#rownum+1 AS rownum
FROM product
JOIN (SELECT #rownum:=0) AS t
) AS t1
JOIN (SELECT #limit:=CAST('1' AS UNSIGNED) AS thelimit) AS t2
JOIN (SELECT #offset:=2 AS theoffset) AS t3
WHERE t1.rownum>t3.theoffset AND t1.rownum <= t2.thelimit+t3.theoffset;
A detailed explanation is below:
The table t1 is generated by the following query:
SELECT product.*, #rownum:=#rownum+1 AS rownum
FROM product
JOIN (SELECT #rownum:=0) AS t
In this query we practically select everything from the product table and attach a row number counter to every fetched row from it (using the #rownum variable which increments with 1 for every row).
The t2 table
SELECT #limit:=CAST('1' AS UNSIGNED) AS thelimit
is just your limit clause stored as variable.
The t3 table
SELECT #offset:=5 AS theoffset
is your offset
We then join those three tables and we apply condition
WHERE t1.rownum>t3.theoffset AND t1.rownum <= t2.thelimit+t3.theoffset;
by which we are simulating a regular LIMIT clause.
Furthermore - if you wish, you can use just #limit and #offset instead of t2.thelimit and t3.theoffset - it will work fine and it will be probably more readable for some people. The final query can simplify it's look a bit like this:
SELECT t1.*
FROM(
SELECT product.*, #rownum:=#rownum+1 AS rownum
FROM product
JOIN (SELECT #rownum:=0) AS t
) AS t1
JOIN (SELECT #limit:=CAST('1' AS UNSIGNED)) AS t2
JOIN (SELECT #offset:=2) AS t3
WHERE rownum>#offset AND rownum <= #limit+#offset;
or you can even skip the two JOINs if you declare the variables before executing the query (this may be a bit faster):
SET #limit:=CAST('1' AS UNSIGNED);
SET #offset:=2;
SELECT t1.*
FROM(
SELECT product.*, #rownum:=#rownum+1 AS rownum
FROM product
JOIN (SELECT #rownum:=0) AS t
) AS t1
WHERE rownum>#offset AND rownum <= #limit+#offset;

SQL: A column in a subquery does not appear

There is a query in MySQL 5.7:
SELECT * FROM
(
SELECT (#rowNum:=#rowNum+1) AS rowNo,t.* FROM table_target t,(SELECT (#rowNum :=0)) AS b
WHERE p_d = '2020-11-08'
ORDER BY kills DESC
) t
WHERE t.uid= '8888'
Running this query, there is no exception but column B disappears and if using select b from in the outter query, it returns unknown column exception.
I have 2 questions:
Why the (SELECT (#rowNum :=0)) does not appear?
Is the (#rowNum:=#rowNum+1) equivelent to row_number() over () in Oracle? If so, how to understand it...
Thanks for your help in advance.
In addition, I just found if I put the (SELECT (#rowNum :=0) ) in the left:
...
SELECT (SELECT (#rowNum :=0) ) AS b, (#rowNum:=#rowNum+1) AS rowNo , t.* FROM table_target t
...
Then the row number column does not increase any more, why could this happen?
You have asked 3 questions here:
Question 1: Why the (SELECT (#rowNum :=0)) does not appear?
Answer: You have used (SELECT (#rowNum :=0)) as B as a table joining it but not calling it in column list after select. That's why it is not showing it in output. You have called it as (#rowNum:=#rowNum+1) which is showing the value after increment means starting from 1.
Question 2: Is the (#rowNum:=#rowNum+1) equivalent to row_number() over () in Oracle? If so, how to understand it
Answer: Yes, it is equivalent. MySql 8.0 and above also support this (known as window function). It works as:
At the time of initialization of the query (SELECT (#rowNum :=0)) variable #rowNum will be initialized with value 0.
When we are calling (#rowNum:=#rowNum+1) in select then it will add 1 in #rowNum and assign it to itself for every row returned by select query.
This is how it will print the row number.
Question 3: if I put the (SELECT (#rowNum :=0) ) in the left:
Answer: If you put the (SELECT (#rowNum :=0) ) as field list after select then it will initialize the value of #rownum to 0 in every row returned by select. This is why you will not get incremented value.
The column "disappears" because the value is NULL. MySQL does not guarantee the order of evaluation of expressions in the SELECT, the initialization might not work.
Second, you code does not do what you intend, even if that worked, because variables may not respect the ORDER BY. I think you intend:
select k.*
from (select (#rownum := #rownumn + 1) as rownum, k.*
from (select k.*
from kills k
where k.p_d = '2020-11-08'
order by kills desc
) k cross join
(select #rownum := 0) params
) k
where t.uid = '8888';
There are probably better ways to do what you want. But your question is specifically about variables and MySQL 5.7.

Changing sql to get rid of windowed functions

I'm trying to create a view on a remote mysql database and unfortunately it appears that the version installed (5.7) does not support window functions. Everything worked on my local database but now I'm a little stuck.
Here's previous code:
create or replace view my_view as
(
with a as
(select a.*, DENSE_RANK() over (partition by SHOP order by TIMESTAMP(LOAD_TIME) DESC) rn
from my_table as a)
select row_number() OVER () as id, SHOP, LOAD_TIME from a WHERE a.rn = 1
);
Mysql 5.7 doesnt support CTE either, but that isn't a big problem.
Any hints how to solve this?
Replacing the dense_rank() is pretty easy. However, replacing the row_number() is more difficult. MySQL does not allow variables in views. Unfortunately, that leaves you with an inefficient subquery for the row number as well:
select (select count(distinct shop)
from mytable t2
where t2.shop <= t.shop
) as id,
shop, load_time
from mytable t
where t.load_time = (select max(t2.load_time) from mytable t2 where t2.shop = t.shop);
Or, if these are the only two columns you have, use aggregation:
select (select count(distinct shop)
from mytable t2
where t2.shop <= t.shop
) as id,
shop, max(load_time) as load_time
from mytable t
group by shop;
This is not efficient. In a simple query, you could use variables:
select (#rn := #rn + 1) as id,
shop, load_time
from mytable t cross join
(select #rn := 0) params
where t.load_time = (select max(t1.load_time) from mytable t1 where t1.shop = t.shop);
If performance is an issue, then you may want to create a table rather than a view and keep it up-to-date using triggers.
You can handle the filtering part with a correlated subquery:
create or replace view my_view as
select shop, load_time
from mytable t
where t.load_time = (select max(t1.load_time) from mytable t1 where t1.shop = t.shop)

Rank values in Mysql

I am having trouble finding a solution. I need to make a column that rank from the most to the least value (column bedrag). If the values are the same then the value with the highest number ( column spelersnr ) 'wins'.
I hope you can help me out.
This is what I got so far.
SELECT s.spelersnr,
naam ,
(select max(bedrag) from boetes b where b.spelersnr = s.spelersnr) as mbedrag,
#curRank := #curRank + 1 AS POSITIE
FROM spelers s, (SELECT #curRank := 0) r
ORDER BY mbedrag ;
Given that you are using MySQL 8+, you may try using the ROW_NUMBER function here. Also, we can rewrite your query using a join, to eliminate the correlated subquery in the select clause:
SELECT s.spelersnr, s.naam,
ROW_NUMBER() OVER (ORDER BY b.mbedrag DESC, s.spelersnr DESC) rn
FROM spelers s
INNER JOIN
(
SELECT spelersnr, MAX(bedrag) AS mbedrag
FROM boetes
GROUP BY spelersnr
) b
ON s.spelersnr = b.spelersnr
ORDER BY
b.mbedrag;

sort by MySQL special group

Table A shows results that I have by running the following SQL in MySQL.
SELECT * FROM table
WHERE MATCH (title) AGAINST ('marka tv')
Table A
Table B shows results that I want to get. As you can see the groups are in round-robin order.
Table B
If I understand the question, you want to sort the output so the groups are in a round-robin fashion rather than ordered. You can do this by enumerating the values within each group and then using that information for sorting:
SELECT t.*
FROM (SELECT t.*,
(#rn := if(#g = groups, #rn + 1,
if(#g := groups, 1, 1)
)
) as rn
FROM table t CROSS JOIN
(SELECT #rn := 0, #g := '') params
WHERE MATCH (title) AGAINST ('marka tv')
ORDER BY groups
) t
ORDER BY rn, groups;
Consider a subquery in a derived table to calculate a group number to be sorted at final table:
SELECT f.*
FROM
(SELECT t1.* ,
(SELECT count(*)
FROM table t2
WHERE (t2.title <= t1.title)
AND (t1.groups = t2.groups)) AS groupNo
FROM table t1
WHERE MATCH (t1.title) AGAINST ('marka tv')
) AS f
ORDER BY groupNo, groups