Cannot Create VIew on MySQL - mysql

It's Possible to Create this VIEW on MySQL? The problem is with the variables. I can't find a way around it.
CREATE VIEW vw_ranking AS
SELECT rank.ativid_id, rank.user_id, b.nome, rank.quant
FROM
(SELECT user_id, ativid_id, quant,
#ativ_rank := IF(#current_ativ = ativid_id, #ativ_rank + 1, 1) AS ativ_rank,
#current_ativ := ativid_id
FROM (SELECT ativid_id, user_id, COUNT(user_id) as quant FROM tb_registro_ativ
GROUP BY ativid_id, user_id) atividade
ORDER BY ativid_id, quant DESC
) rank INNER JOIN tb_usuarios b ON rank.user_id = b.user_id
WHERE ativ_rank <= 10;

You cannot define variables with view creation.
Source: https://dev.mysql.com/doc/refman/5.5/en/create-view.html
A view definition is subject to the following restrictions:
The SELECT statement cannot contain a subquery in the FROM clause.
The SELECT statement cannot refer to system variables or user-defined
variables.
Within a stored program, the SELECT statement cannot refer to program
parameters or local variables.
The SELECT statement cannot refer to prepared statement parameters.
Any table or view referred to in the definition must exist. After the
view has been created, it is possible to drop a table or view that the
definition refers to. In this case, use of the view results in an
error. To check a view definition for problems of this kind, use the
CHECK TABLE statement.
I suggest you use a stored procedure instead.

Views are severely limited in MySQL. You cannot use variables and you cannot use subqueries in the FROM clause.
Your query is quite complicated. You can use subqueries in the SELECT, and that often makes it possible to calculate ranks -- at least on small tables. In your case, you might need a series of views to accomplish what you want.

Related

What does AS followed by some queries mean at SQL?

I know AS is used to create an alias name in SQL. I know with is used if you want to save results of intermediate query or create a temp table. For example, something like the following:
with new_table as
(select * from order where order.id is Not NULL)
So the above query lets you reuse the new_table in another query. However what if you do not include with and write the following:
new_value as
(
select
A as Age,
W as weight
from
order
)
The as inside the select are creating the alias but what does the new_value as do?
it is different than with new_value as ?
For a single query, there is one WITH that can apply to multiple comma-separated CTEs. The CTEs are then followed by the main part of the query that can reference them.
For example,
WITH
mycte1 AS
(SELECT 1 as a),
mycte2 AS
(SELECT 1 as b),
mycte3 AS
(SELECT * FROM mycte1 INNER JOIN mycte2 ON a=b)
SELECT *
FROM mycte3
The CTE mycte1 isn't special just because it follows the WITH. The WITH is for all 3 CTEs (mycte1, mycte2, and mycte3).
Note that even though the order of the CTEs matters in this case (mycte3 needs to be defined after mycte1 and mycte2 since it references them), that's not because any of the CTEs is specially linked to the WITH.
You cannot write CTEs without the WITH.
You can read more in the documentation for CTEs/WITH.

why there is performance difference when retrieving data from view vs underlying select of that view

I am doing query on view with single predicates which gives me the record in 4-7 seconds, but when i try to retrieve the record with same predicate and directly with underlying query from that view it gives me records in less then seconds. I am using MySQL.
I have tried checking the execution plan of both the query and it gives major differences if i have hundreds of thousands of records in tables.
So any clue or idea why performance is better when using query directly?
Following is my view definition
SELECT entity_info.source_entity_info_id AS event_sync_id,
entity_info.source_system_id AS source_system_id,
entity_info.target_system_id AS destination_system_id,
event_sync_info.integrationid AS integration_id,
event_sync_info.source_update_time AS last_updated,
entity_info.source_internal_id AS source_entity_internal_id,
entity_info.source_entity_project AS source_entity_project,
entity_info.target_internal_id AS destination_entity_internal_id,
entity_info.destination_entity_project AS destination_entity_project,
entity_info.source_entity_type AS source_entity_type,
entity_info.destination_entity_type AS destination_entity_type,
event_sync_info.opshub_update_time AS opshub_update_time,
event_sync_info.entity_info_id AS entity_info_id,
entity_info.global_id AS global_id,
entity_info.target_entity_info_id AS target_entity_info_id,
entity_info.source_entity_info_id AS source_entity_info_id,
(
SELECT Count(0) AS count(*)
FROM ohrv_failed_event_view_count failed_event_view
WHERE ((
failed_event_view.integration_id = event_sync_info.integrationid)
AND (
failed_event_view.entityinfo = entity_info.source_entity_info_id))) AS no_of_failures
FROM (ohrv_entity_info entity_info
LEFT JOIN ohmt_eai_event_sync_info event_sync_info
ON ((
entity_info.source_entity_info_id = event_sync_info.entity_info_id)))
WHERE (
entity_info.source_entity_info_id IS NOT NULL)
Query examples
select * from view where integration_id=10
Execution plan of this processes 142668 rows for sub query that is there in this view
select QUERY_OF_VIEW and integration_id=10
Execution plan of this looks good and only required rows are getting processed.
I think the issue is in the following query:
SELECT * FROM view WHERE integration_id = 10;
This forces MySQL to materialize an intermediate table, against which it then has to query again to apply the restriction in the WHERE clause. On the other hand, in the second version:
SELECT (QUERY_OF_VIEW with WHERE integration_id = 10)
MySQL does not have to materialize anything other than the query in the view itself. That is, in your second version MySQL just has to execute the query in the view, without any subsequent subquery.
refereeing to this link of documentation you can see,that its depend on if the MERGE algorithm can used it will , but if its not applicable so new temp table must generated to find the relations of data, also you can see this answer that talking about optimization and when to use view and when you should not .
If the MERGE algorithm cannot be used, a temporary table must be used
instead. MERGE cannot be used if the view contains any of the
following constructs:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
LIMIT
UNION or UNION ALL
Subquery in the select list
Refers only to literal values (in this case, there is no underlying
table)

Save order of SELECT result in complex query

I need to sort selected_booking by cost first and then assign the index i to every row. My variant doesn't work properly (outer SELECT breaks the order):
SELECT (#i:=#i + 1) AS i, selected_booking.*
FROM (SELECT * FROM booking ORDER BY cost DESC) AS selected_booking;
Is there any way to save the order of inner selection when doing outer one?
Q: Is there any way to save the order of inner selection when doing outer selection?
A: Absent an ORDER BY clause on the outer query, MySQL is free to return the rows in any order it chooses.
If you want rows from the inline view (derived table) returned in a specific order, you need to specify that in the outer query... you'd need to add an ORDER BY clause on the outer query.
NOTE: The behavior of user-defined variables as in your query is not guaranteed, the MySQL Reference Manual warns of this. But in spite of that warning, we do observe repeatable behavior in MySQL 5.1 and 5.5.
It's not at all clear why you need an inline view (aka a derived table, in the MySQL venacular) in the example you give.
It seems like this query would return the result you seem to want:
SET #i = 0 ;
SELECT #i:=#i+1 AS i
, b.*
FROM booking b
ORDER BY b.cost DESC ;
Alternatively, you could do this in a single statement, and initialize #i within the query, rather than a separate SET statement.
SELECT #i:=#i+1 AS i
, b.*
FROM booking b
JOIN (SELECT #i:=0) i
ORDER BY b.cost DESC
(This initialization works, again, because of the way the MySQL processes inline views, the inline view query is run BEFORE the outer query. This isn't guaranteed behavior, and may change in a future release (it may have already changed in 5.6)
NOTE: For improved performance of this query, if a suitable index is available with cost as the leading column, e.g.
... ON booking (cost)
that may allow MySQL to use that index to return rows in order and avoid a "Using filesort" operation.

Call a user-defined function inside a CTE for every row returned from another CTE

I have a query with a CTE that returns multiple rows, I want to execute a Function for every row returned.
Is it possible, I checked on google, it says about using temp table to populate the result. I just want to confirm
with job_list as ( select JOB_ID,CREATED_DATE from job_table) ,
app_list as (select APP_ID from job_list jobs, dbo.fnGetApp(jobs.JOB_ID,9))
select * from job_list, app_list
This is not the exact query, I have simplified for understanding the problem I face.
dbo.fnGetApp is a function that takes two params varchar and int and returns a table of a single column (varchar APP_ID)
Error - The multi-part identifier "jobs.JOB_ID" could not be bound.
I want to run the function for every row returned by the job_list CTE and use the results as a CTE for another query which uses both the CTEs
Thanks
David
Can't you do it like this:
with job_list as
(
select
JOB_ID,
CREATED_DATE
from
job_table
),
app_list as
(
select
APP_ID
from
job_list AS jobs
CROSS APPLY dbo.fnGetApp(jobs.JOB_ID,9) AS something
)
select * from
job_list,
app_list
If you want to call a method, then you need to use a cursor, but if you want to call a function then you should be able to achieve this with joins.
I might be missing something, but I'm not quite sure why you feel you need to embed a subselect in this code.
The CTE creates the equivalent of a temporary table, and the fields are all accessible to the subsequent query, so simply refer to those fields in your internal function.
Perhaps if you posted the actual query you're using it might make more sense :)

MySQL user-defined function for getting the modal value of a column?

For example:
SELECT MODE(field) FROM table
In another mode, what user-defined function can I use to get the most common value of a column?
I know I can do something like:
SELECT field, COUNT(*) as total FROM table GROUP BY field ORDER BY total DESC LIMIT 1
But I have to query other data in the same MySQL statement too, so I have to use a user-defined function.
Thank you.
Here's a link to MySQL's documentation on aggregate functions. It looks like they don't have anything for "mode", so I would say that your second query is probably your best shot.
MySQL doesn't support user-defined aggregate functions (PostgreSQL does, for what it's worth). You can't use a UDF to do what you want in MySQL.
You can do it for example by putting the mode-computation in a derived table subquery:
SELECT t.*
FROM (SELECT field AS mode, COUNT(*) as total FROM table
GROUP BY field ORDER BY total DESC LIMIT 1) AS m
JOIN table t ON m.mode = t.field;