Window function in MySQL queries - mysql

Is there a way to use window functions in MySQL queries dynamically within a SELECT query itself? (I know for a fact that it is possible in PostgreSQL).
For example, here is the equivalent query in PostgreSQL:
SELECT c_server_ip, c_client_ip, sum(a_num_bytes_sent) OVER
(PARTITION BY c_server_ip) FROM network_table;
However, what would be the corresponding query in MySQL?

Starting MySQL 8.0, you can now use OVER and partition, so consider upgrading to the latest version :)

Hope this might work:
select A.c_server_ip, A.c_client_ip, B.mySum
from network_table A, (
select c_server_ip, sum(a_num_bytes_sent) as mySum
from network_table group by c_server_ip
) as B
where A.c_server_ip=B.c_server_ip;

Related

What's the equivalent syntax in MySQL for `with xxx AS ()`

In MSSQL, I have a query something like:
WITH temp AS (
SELECT
*
FROM
xx.xxxx
)
But WITH temp AS () isn't supported in MySQL syntax, I wonder what the equivalent syntax should be in MySQL Workbench? Thanks.
Below is a screenshot of the syntax error:
If you have MySQL 5.x and you need to adapt the query which contains CTE, then convert
WITH cte AS (cte query text)
SELECT ...
FROM cte
...
to
SELECT ...
FROM (cte query text) cte
...
If there is more than one CTE then perform this substitution with accuracy from latter CTE to former one (you may need to use multiple copies of some CTE subquery text - this is a norma).

Alternative to using Variable in a View

I need some assistance building a SQL statement that will output the top 5 retired assets per client that can be put into a SQL View.
I have built the following SQL statement but it will not work within a view and need an alternative.
SET #row_number := 0;
SELECT DISTINCT NAME, RetiredDate, COMMENT,
#row_number:=CASE WHEN #client_ID=clientID THEN #row_number+1 ELSE 1 END AS num,
#client_ID:=clientID ClientID
FROM `retiredassets`
WHERE `retiredassets`.`ClientID` IN(SELECT clientID FROM `clients`)
HAVING num <=5
Does anyone have any suggestions for me? The above statement works flawlessly but cannot work within a SQL View.
In MySQL 8.0 this should be:
WITH cte AS (
SELECT r.NAME, r.RetiredDate, r.COMMENT,
ROW_NUMBER() OVER (PARTITION BY r.ClientID ORDER BY ...) AS num,
r.ClientID
FROM retiredassets
JOIN clients USING (ClientID)
)
SELECT * FROM cte WHERE num <= 5;
I left ... because I don't know what your ordering is. Your original query doesn't specify an order, so you'll have to choose one.
Re your comment.
If you can't upgrade to MySQL 8.0, and you can't use variables in a VIEW definition, then you can't use a VIEW. You will have to write out the full query when you use it, until you can upgrade to MySQL 8.0.

Alternative for PERCENTILE_CONT in MySQL/MariaDB

I want to calculate percentile_cont on this table.
In Oracle, the query would be
SELECT PERCENTILE_CONT(0.05) FROM sometable;
What would be it's alternative in MariaDB/MySQL?
While MariaDB 10.3.3 has support for these functions in the form of window functions (see Lukasz Szozda's answer), you can emulate them using window functions in MySQL 8 as well:
SELECT DISTINCT first_value(matrix_value) OVER (
ORDER BY CASE WHEN p <= 0.05 THEN p END DESC /* NULLS LAST */
) x,
FROM (
SELECT
matrix_value,
percent_rank() OVER (ORDER BY matrix_value) p,
FROM some_table
) t;
I've blogged about this more in detail here.
MariaDB 10.3.3 introduced PERCENTILE_CONT, PERCENTILE_DISC, and MEDIAN windowed functions.
PERCENTILE_CONT
PERCENTILE_CONT() (standing for continuous percentile) is an ordered set aggregate function which can also be used as a window function. It returns a value which corresponds to the given fraction in the sort order. If required, it will interpolate between adjacent input items.
SELECT name, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY star_rating)
OVER (PARTITION BY name) AS pc
FROM book_rating;
There is no built in function for this in either MariaDB or MySQL, so you have to solve this on the SQL level (or by adding a user defined function written in C ...)
This might help with coming up with a SQL solution:
http://rpbouman.blogspot.de/2008/07/calculating-nth-percentile-in-mysql.html
MariaDB 10.2 has windowing functions.
For MySQL / older MariaDB, and assuming you just want the Nth percentile for a single set of values.
This is best done form app code, but could be built into a stored routine.
Count the total number of rows: SELECT COUNT(*) FROM tbl.
Construct and execute a SELECT with LIMIT n,1 where n is computed as the percentile times the count, then filled into the query.
If you need to interpolate between two values, it gets messier. Do you need that, too?

Can not Access Aliased Columns in Select Statement (MySQL)

I have a problem with Aliased Columns in MySQL!
My Query:
SELECT Price AS Pr, (Pr*10/100) FROM MyTable;
MySQL WorkBench Error: UnKnown Column 'Pr' in Field List !!!
I tested my query in W3Schools with no error !
I tested my query in W3Schools with no error!
This doesn't prove that your query is valid.
You can only use aliases in GROUP BY, ORDER BY or HAVING clauses. Your usage variant is not allowed, because the value of alias is not known when MySQL is selecting the 2-nd column.
I've got a suspicion that W3Schools uses MS Access to run user queries, and MS Access does allow such atrocity as referencing column aliases in a SELECT clause that are defined in the same SELECT clause.
The standard doesn't allow this and MySQL does follow standard in this particular case.
As for solution to your problem, I can see two options.
The more generic solution, which would run in probably any SQL product, would be to use a derived table:
SELECT
Pr,
(Pr * 10 / 100) AS SomethingElse
FROM
(
SELECT
SomeComplexExpression AS Pr
FROM MyTable
) AS sub
;
The other option would be to use a variable, which is MySQL-specific:
SELECT
#Pr := SomeComplexExpression AS Pr,
(#Pr * 10 / 100) AS SomethingElse
FROM MyTable
;
Finally, if you need to test/demonstrate if something can/cannot work in MySQL, I'd recommend using SQL Fiddle.

MySql using correct syntax for the over clause

What is the correct syntax to get the over clause to work in mysql?
I would like to see the total sms's sent by each user without grouping it with the group by clause.
SELECT
username,
count(sentSmsId) OVER (userId)
FROM
sentSmsTable,
userTable
WHERE
userId = sentUserId;
MySQL 8 has got the window functions! Therefore, you can write your query in it like this:
SELECT username,
count(sentSmsId) OVER (partition by userId)
FROM sentSmsTable
JOIN userTable ON userId = sentUserId;
There is no OVER clause in MySQL that I know of, but here is a link that might assist you to accomplish the same results:
http://explainextended.com/2009/03/10/analytic-functions-first_value-last_value-lead-lag/
Hope this helps.
MySQL does not currently support window functions, so over() will only yield syntax errors (or garbage, if it's accepted regardless).
MySQL Doesn't have window functions until the most recent release: MySQL 8 (release in April, 2018). MS SQL Server also accepts OVER clause.
The syntax is:
function(col1) OVER (PARTITION BY col2 ORDER BY col3)
Check out https://mysqlserverteam.com/mysql-8-0-2-introducing-window-functions/ for more examples.