MySQL UNION not working - mysql

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.

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

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

Error in creating view

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.

select next/previous 10 rows in mysql

I have a list that displays only 10 rows.
I need to select the next 10 and previous 10 rows.
However, the ID I use as reference are not exactly in order.
e.g:
1,2,5,10,15
How do I select the next few rows using the ID?
you can try limit:
select * from `table` limit <startIndex>,<NumberOfRecords>;
example:-
select * from `user` limit 5,10;
This will return 10 rows starting from 6th row.
a possible query would be
SELECT * FROM mytable WHERE id > current_id LIMIT 10
for the 10 previous
SELECT * FROM mytable WHERE id < current_id ORDER BY id DESC LIMIT 10
First select 10 first value:
SELECT * FROM `leave_type` ORDER BY id asc limit 10;
and then
select * from `leave_type` limit 10, 10;
will show rows after 10th value(range of 10) and start with 11th.
(
SELECT *
FROM mytable
WHERE id < $myid
ORDER BY
id DESC
LIMIT 10
)
UNION ALL
(
SELECT *
FROM mytable
WHERE id >= $myid
ORDER BY
id
LIMIT 10
)
ORDER BY
id
You can use limit keyword of MySQL.