Error in creating view - mysql

I got the error #1349 - View's SELECT contains a subquery in the FROM clause
mycode is:
CREATE VIEW `MyViewName` AS
SELECT *
FROM
(SELECT *
FROM (
(SELECT *
FROM `crm_clients`
WHERE ctype=1
ORDER BY rand() LIMIT 0,
3)
UNION
(SELECT *
FROM `crm_clients`
WHERE ctype=1
ORDER BY rand() LIMIT 0,
3)
UNION
(SELECT *
FROM `crm_clients`
WHERE ctype=1
ORDER BY rand() LIMIT 0,
3)
UNION
(SELECT *
FROM `crm_clients`
WHERE ctype=1
ORDER BY rand() LIMIT 0,
3)) t
ORDER BY rand())
what is the problem with this code?I am not familier with view

MySQL does not allow subqueries in the from clause when you define views.
You can do what you want as:
Create View `MyViewName` as
(SELECT * FROM `crm_clients` WHERE ctype=1 order by rand() limit 0,3)
union
(SELECT * FROM `crm_clients` WHERE ctype=1 order by rand() limit 0,3)
union
(SELECT * FROM `crm_clients` WHERE ctype=1 order by rand() limit 0,3)
union
(SELECT * FROM `crm_clients` WHERE ctype=1 order by rand() limit 0,3)
order by rand();
My guess is that you actually want to change the ctype values as well. Otherwise the query is rather strange.
Here are the restrictions on views.

Related

Select n random rows per group in MySQL 5.7

Can I somehow combine these two queries into one in MySQL 5.7 without global variables and stored procedures?
define p1_id, p2_id int;
...
insert into Cards_in_game_decks select * from Cards_in_decks where Cards_in_decks.player_id=p1_id order by rand() limit 10;
insert into Cards_in_game_decks select * from Cards_in_decks where Cards_in_decks.player_id=p2_id order by rand() limit 10;
You just need to do a union:
insert into Cards_in_game_decks select * from (
(select * from Cards_in_decks where Cards_in_decks.player_id=p1_id order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=p2_id order by rand() limit 10)
) random_cards
fiddle
To get up to 10 cards per player for up to 6 players listed in a Players table, you just have to get repetitive:
insert into Cards_in_game_decks select * from (
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 0,1) order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 1,1) order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 2,1) order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 3,1) order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 4,1) order by rand() limit 10)
union all
(select * from Cards_in_decks where Cards_in_decks.player_id=(select id from Players where game_id=1 order by id limit 5,1) order by rand() limit 10)
) random_cards
fiddle
There are likely much better ways to do this in mysql 8.

Simplify SQL query of multiple SELECT statements, each with UNION and LIMIT

Need assistance with simplifying this SQL query to possibly a single SELECT:
(SELECT * FROM `deals`
WHERE category_id = 1
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 2
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 4
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 5
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 6
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 8
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 9
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 10
ORDER BY id desc
LIMIT 10)
UNION
(SELECT * FROM `deals`
WHERE category_id = 17
ORDER BY id desc
LIMIT 10)
I've been told to try using GROUP BY and HAVING. However, any query I tried didn't work in the slightest...
Any help will be greatly appreciated!
EDIT - apologies, forgot to mention database engine is MySQL
You can condense this down with a window function to limit each group bucket to 10.
SELECT
*
FROM
(
SELECT
*,
ROW_NUMBER() OVER PARTITION BY(category_id ORDER BY id DESC) AS GroupOrder
FROM `deals`
WHERE category_id BETWEEN 1 AND 10
)AS X
WHERE
GroupOrder<=10
I'm not sure, I need to know if you need that limit of 10, is this like take top 10 of all those things?
if not then
SELECT * FROM `deals`
WHERE category_id between 0 and 10 or category_id=17
ORDER BY category_id asc, id desc
For older versions of MySQL without the windowing functions, here is the code.
SELECT T1.ID, T1.Category_ID, T1.Name
FROM (
SELECT #row_num := IF(#prev_value=concat_ws('',t.Category_ID),#row_num+1,1) AS RowNumber
,t.*
,#prev_value := concat_ws('',t.Category_ID)
FROM data t,
(SELECT #row_num := 1) x,
(SELECT #prev_value := '') y
ORDER BY t.Category_ID
) T1
WHERE T1.RowNumber < 10
AND T1.Category_ID IN (1,2,3,4,5,6,7,8,9,10)
You will need to add the necessary field names to the other select.
This uses the technique described here

MySQL UNION not working

I'm attempting a mysql union but nothing is returned? Below is an example. In total there is 16 select queries
$url_array = array(
"euro-gbp","euro-aud","euro-usd",
"euro-jpy","gbp-jpy","euro-cad",
"usd-cad","usd-jpy","cad-jpy",
"gbp-usd","aud-usd","gbp-cad",
"aud-cad","aud-jpy","aud-nzd",
"euro-nzd","gbp-aud","gbp-nzd",
"nzd-usd","nzd-cad","nzd-jpy");
foreach($url_array as $urls) {
$sql[]= "SELECT *
FROM `data_analysis_child`
WHERE type='".$urls."'
ORDER BY id DESC
LIMIT 2";
}
$sql = implode(" UNION ",$sql);
The sql result
SELECT * FROM `data_analysis_child` WHERE type='euro-gbp' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='euro-aud' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='euro-usd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='euro-jpy' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='gbp-jpy' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='euro-cad' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='usd-cad' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='usd-jpy' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='cad-jpy' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='gbp-usd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='aud-usd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='gbp-cad' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='aud-cad' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='aud-jpy' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='aud-nzd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='euro-nzd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='gbp-aud' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='gbp-nzd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='nzd-usd' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='nzd-cad' ORDER BY id DESC LIMIT 2 UNION SELECT * FROM `data_analysis_child` WHERE type='nzd-jpy' ORDER BY id DESC LIMIT 2
How do i solve? Is there a better way to restructure this query?
if you need order by and limit for each select you should use () around each select
foreach($url_array as $urls) {
$sql[]= " ( SELECT * FROM `data_analysis_child` WHERE type='".$urls."' ORDER BY id DESC LIMIT 2 )";
break;
}
Just a little addition to do that. If you are getting ZERO results then use UNION ALL instead of only UNION. Actually duplicate records are avoided in UNION but with UNION ALL you will get everything that a query is returning. give it a try !!!
The documentation of UNION clearly explains:
To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
It also says:
Note
Previous versions of MySQL may permit such statements without parentheses. In MySQL 5.7, the requirement for parentheses is enforced.
If you are using MySQL 5.7 or newer, the code doesn't return anything because the query doesn't run. You should check the type of the returned value (the query functions return FALSE when the query is invalid) and the error message.
You could do this:
SELECT *
FROM (
SELECT #rank := if (#last_type=type, #rank+1, 1) as type_rank, *
FROM data_analysis_child
WHERE type IN ('euro-gbp', 'euro-aud', 'euro-usd'....)
ORDER BY id DESC
)
WHERE type_rank<=2;
But the performance will suck.
Depending on how the indexes are configured and assuming that your id column is unique this might be better:
SELECT 'first', dac1.*
FROM data_analysis_child dac1
WHERE dac1.id IN (
SELECT MAX(dac2.id)
FROM data_analysis_child dac2
WHERE dac2.type IN ('euro-gbp', 'euro-aud', 'euro-usd'....)
GROUP BY dac2.type
)
UNION
SELECT 'second', dac3.*
FROM data_analysis_child dac3
WHERE dac3.id IN (
SELECT MAX(dac4.id)
FROM data_analysis_child dac4
WHERE dac4.type IN ('euro-gbp', 'euro-aud', 'euro-usd'....)
AND dac4.id NOT IN (
SELECT MAX(dac5.id)
FROM data_analysis_child dac5
WHERE dac5.type IN ('euro-gbp', 'euro-aud', 'euro-usd'....)
GROUP BY dac5.type
)
GROUP BY dac4.type
)
But it does not scale well to getting the top N values for each type.
A better solution would be to to flag the state of the first or second rank as an attribute on the record and filter directly.

Combine two mysql queries with two different order by statements

I want to combine these two queries.
SELECT * FROM table1 WHERE status='pending' and adr='' order by id desc limit 0,1;
SELECT * FROM table1 where status='pending' and adr='new' ORDER BY RAND() LIMIT 1
You can use a UNION ALL set operator to concatenate the results of the two queries
( SELECT * FROM table1 WHERE status='pending' AND adr='' ORDER BY id DESC LIMIT 1 )
UNION ALL
( SELECT * FROM table1 WHERE status='pending' AND adr='new' ORDER BY RAND() LIMIT 1 )
Reference: UNION ALL https://dev.mysql.com/doc/refman/5.5/en/union.html

MySQL: Sum of multiple subqueries

I need to order a MySQL query by the resulting SUM of multiple subqueries.
Here's some example code for what I'm trying to do:
SELECT ...
(SELECT SUM(
(SELECT one_result ... LIMIT 1) as plays1,
(SELECT one_result ... LIMIT 1) as plays2,
(SELECT one_result ... LIMIT 1) as plays3
)) as total_plays
FROM plays
ORDER BY total_plays
Basically, I need to run three subqueries that'll each return an integer.
I need to order the entire query by the SUM() of these integers.
When I try to run this query I get a syntax error.
Could someone let me know what the proper syntax is for summing multiple subqueries?
I've also already tried:
SELECT ...
(SELECT one_result ... LIMIT 1) as plays1,
(SELECT one_result ... LIMIT 1) as plays2,
(SELECT one_result ... LIMIT 1) as plays3
SUM(plays1, plays3, plays3) as total_plays
FROM plays
ORDER BY total_plays
EDIT
#JoeC and #SATSON provided similar answers that solved this. Here's my (working) real query in case this helps anyone else get started on their own query:
````
SELECT song.title as title,
song.file_name as unique_name,
song.artist as artist,
(SELECT difficulty FROM chart WHERE id = song.easy_chart ORDER BY scoring_version ASC LIMIT 1) as easy_difficulty,
(SELECT difficulty FROM chart WHERE id = song.hard_chart ORDER BY scoring_version ASC LIMIT 1) as hard_difficulty,
(SELECT difficulty FROM chart WHERE id = song.master_chart ORDER BY scoring_version ASC LIMIT 1) as master_difficulty,
(plays.easy_plays + plays.hard_plays + plays.master_plays) as total_plays
FROM song
INNER JOIN (SELECT parent_song_id,
(SELECT global_plays ORDER BY scoring_version ASC LIMIT 1) as easy_plays,
(SELECT global_plays ORDER BY scoring_version ASC LIMIT 1) as hard_plays,
(SELECT global_plays ORDER BY scoring_version ASC LIMIT 1) as master_plays
FROM chart) as plays
ON plays.parent_song_id = song.id
ORDER BY total_plays DESC
LIMIT 9
OFFSET 0
````
Ummm, what about
SELECT *, plays1 + plays2 + plays3 as total_play from
(SELECT ...
(SELECT one_result ... LIMIT 1) as plays1,
(SELECT one_result ... LIMIT 1) as plays2,
(SELECT one_result ... LIMIT 1) as plays3
FROM plays)
ORDER BY total_plays
Try Like this
SELECT sum(plays1) as total_plays from (
(SELECT one_result as plays1 ... LIMIT 1)
union all
(SELECT one_result as plays1 ... LIMIT 1 )
union all
(SELECT one_result as plays1 ... LIMIT 1)
)
as plays
ORDER BY total_plays