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.
Related
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.
This may sound like an odd question, but I'm curious to know if it's possible...
Is there a way to simulate MySQL records using inline data? For instance, if it is possible, I would expect it to work something like this:
SELECT inlinedata.*
FROM (
('Emily' AS name, 26 AS age),
('Paul' AS name, 56 AS age)
) AS inlinedata
ORDER BY age
Unfortunately MySQL does not support the standard values row-constructor for this kind of things, so you need to use a "dummy" select for each row and combine the rows using UNION ALL
SELECT *
FROM (
select 'Emily' AS name, 26 AS age
union all
select 'Paul', 56
) AS inlinedata
ORDER BY age
The UNION ALL serves two purposes
It preserves any duplicate you might have on purpose
It's a (tiny) bit faster than a plain UNION (because it does not check for duplicates)
No, not without making it complicated, but you can create a temporary table and query that instead. Temporary tables are deleted when the current client session terminates.
You can query them and insert data into them just like with other tables. When you create them, you have to use the TEMPORARY keyword, like so:
CREATE TEMPORARY TABLE ...
This way, you can also reuse the data for multiple queries if needed, no data gets stored, and all records that you query have the right structure (whereas the syntax you give in your example would create problems when you spell a column name wrong)...
with cte as (
select '2012-04-04' as student_dob, '%test1%' as student_pat
union all
select '2012-05-04', '%test2%'
union all
select '2012-07-04', '%test3%'
union all
select '2012-05-11', '%test-n%'
)
select *
from students s
inner join cte c
on s.student_dob = c.student_dob and s.student_name like c.student_pat
arguably that's not a lot more readable, but taking a lead from that, you can just store those in a table or go through temporary table, like Roy suggested.
Also it's not great idea to make a group by student id and select also something else like you did in 2nd query.
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 :)
I am running a complicated and costly query to find the MIN() values of a function grouped by another attribute. But I don't just need the value, I need the entry that produces it + the value.
My current pseudoquery goes something like this:
SELECT MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) FROM (prefiltering) as a GROUP BY a.group_att;
but I want a.* and MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) as my result.
The only way I can think of is using this ugly beast:
SELECT a1.*, COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2)
FROM (prefiltering) as a1
WHERE COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) =
(SELECT MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) FROM (prefiltering) as a GROUP BY a.group_att)
But now I am executing the prefiltering_query 2 times and have to run the costly function twice. This is ridiculous and I hope that I am doing something seriously wrong here.
Possible solution?:
Just now I realize that I could create a temporary table containing:
(SELECT a1.*, COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) as complex FROM (prefiltering) as a1)
and then run the MIN() as subquery and compare it at greatly reduced cost. Is that the way to go?
A problem with your temporary table solution is that I can't see any way to avoid using it twice in the same query.
However, if you're willing to use an actual permanent table (perhaps with ENGINE = MEMORY), it should work.
You can also move the subquery into the FROM clause, where it might be more efficient:
CREATE TABLE temptable ENGINE = MEMORY
SELECT a1.*,
COSTLY_FUNCTION(a1.att1,a1.att2,$v1,$v2) AS complex
FROM prefiltering AS a1;
CREATE INDEX group_att_complex USING BTREE
ON temptable (group_att, complex);
SELECT a2.*
FROM temptable AS a2
NATURAL JOIN (
SELECT group_att, MIN(complex) AS complex
FROM temptable GROUP BY group_att
) AS a3;
DROP TABLE temptable;
(You can try it without the index too, but I suspect it'll be faster with it.)
Edit: Of course, if one temporary table won't do, you could always use two:
CREATE TEMPORARY TABLE temp1
SELECT *, COSTLY_FUNCTION(att1,att2,$v1,$v2) AS complex
FROM prefiltering;
CREATE INDEX group_att_complex ON temp1 (group_att, complex);
CREATE TEMPORARY TABLE temp2
SELECT group_att, MIN(complex) AS complex
FROM temp1 GROUP BY group_att;
SELECT temp1.* FROM temp1 NATURAL JOIN temp2;
(Again, you may want to try it with or without the index; when I ran EXPLAIN on it, MySQL didn't seem to want to use the index for the final query at all, although that might be just because my test data set was so small. Anyway, here's a link to SQLize if you want to play with it; I used CONCAT() to stand in for your expensive function.)
You can use the HAVING clause to get columns in addition to that MIN value. For example:
SELECT a.*, COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2) FROM (prefiltering) as a GROUP BY a.group_att HAVING MIN(COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2)) = COSTLY_FUNCTION(a.att1,a.att2,$v1,$v2);
We want to be able to select top N rows using a SQL Query. The target database could be Oracle or MySQL. Is there an elegant approach to this? (Needless to say, we're dealing with sorted data here.)
To get the top 5 scorers from this table:
CREATE TABLE people
(id int,
name string,
score int)
try this SQL:
SELECT id,
name,
score
FROM people p
WHERE (SELECT COUNT(*)
FROM people p2
WHERE p2.score > p.score
) <=4
I believe this should work in most places.
No. The syntax is different.
You may, however, create views:
/* Oracle */
CREATE VIEW v_table
AS
SELECT *
FROM (
SELECT *
FROM table
ORDER BY
column
)
WHERE rownum <= n
/* MySQL */
CREATE VIEW v_table
AS
SELECT *
FROM table
ORDER BY
column
LIMIT n
I don't think that's possible even just between mysql and mssql. I do an option for simulating such behaviour though:
create views that have an auto incremented int column; say 'PagingHelperID'
write queries like: SELECT columns FROM viewname WHERE PagingHelperID BETWEEN startindex AND stopindex
This will make ordering difficult, you will need different views for every order in which you intend to retreive data.
You could also "rewrite" your sql on the fly when querying depending on the database and define your own method for the rewriter, but I don't think there is any "good" way to do this.
If there is a unique key on the table yes...
Select * From Table O
Where (Select Count(*) From Table I
Where [UniqueKeyValue] < O.UniqueKeyValue) < N
You can substitute your own criteria if you want the "Top" definition to be based on some other logic than on the unique key...
EDIT: If the "sort" that defines the meaning of "Top" is based on a non-unique column, or set of columns, then you can still use this, but you can't guarantee you will be able to get exactly N records out...
Select * From Table O
Where (Select Count(*) From Table I
Where nonUniqueCol < O.nonUniqueCol) < 10
If records 8, 9, 10, 11, and 12 all have the same value in [nonUniqueCol], then the query will either only generate 7 records, (with '<') ... , or 12 (if you use '<=')
NOTE: As this involves a correlated sub-query, the performance can be an issue for very large tables...
Starting with MySQL 8, you can use ROW_NUMBER() filtering to get the semantics of LIMIT (MySQL) or FETCH (Oracle) in a uniform, standards compliant syntax:
SELECT t.a, t.b, t.c, t.o
FROM (
SELECT a, b, c, o, ROW_NUMBER() OVER (ORDER BY o)
FROM x
) t
WHERE rn <= :limit
ORDER BY o
But this is likely to be less efficient than using the vendor specific syntax, so if you have some means of abstracting over LIMIT and FETCH (e.g. using an ORM like jOOQ or Hibernate, or even some templating language), that should be preferred.
The big problem, after looking this over, is that MySQL isn't ISO SQL:2003 compliant. If it was, you'd have these handy windowing functions:
SELECT * from
( SELECT
RANK() OVER (ORDER BY <blah>) AS ranking,
<rest of columns here>,
FROM <table>
)
WHERE ranking <= <N>
Alas, MySQL (and others that mimic it's behavior, eg SQLite), do not, hence the whole limiting issue.
Check out this snippet from Wikipedia (http://en.wikipedia.org/wiki/Window_function_(SQL)#Limiting_result_rows)