I'm trying to select from table data but i want the result not exist in this select.
(SELECT * FROM data WHERE category = 'A' ORDER BY RAND() LIMIT 4)
UNION ALL
(SELECT * FROM data WHERE category = 'B' ORDER BY RAND() LIMIT 4)`
So there are no row that been selected double.
Fiddle with sample data.
With NOT EXISTS:
SELECT * FROM table1 t1
WHERE NOT EXISTS (
SELECT 1 FROM (
(SELECT * FROM table1 WHERE category = 'A' ORDER BY RAND() LIMIT 4)
UNION ALL
(SELECT * FROM table1 WHERE category = 'B' ORDER BY RAND() LIMIT 4)
) t
WHERE t.id = t1.id AND t.category = t1.category
)
See the demo.
SELECT * FROM table1 where id not in (
select id from (
(SELECT * FROM table1 WHERE table1.category = 'A' ORDER BY RAND() LIMIT 4)
UNION ALL
(SELECT * FROM table1 WHERE table1.category = 'B' ORDER BY RAND() LIMIT 4)
)
as t)
Related
I have a users table with 5 columns, id, age, is_premium, is_male, is_customer where id is the primary key.
First statement I do is. This statement has the potential of returning 0 rows:
SELECT * FROM users
WHERE is_premium = 1 AND
is_name = 0 AND
is_customer = 0
Then ONLY from the rows I got from the above query, I want to find the person with the largest age.
SELECT * FROM <from the above query>
WHERE id = (SELECT MAX(ID) <from the above query>)
Question: How do make these 2 separate SQL statements into a single statement and what is the most efficient way of doing this?
why not directly:
SELECT *
FROM users
WHERE is_premium = 1
AND is_name = 0
AND is_customer = 0
ORDER BY age DESC, id ASC
LIMIT 1
for mysql version 8 and above you can also use common table expressions (CTE):
WITH D AS (
SELECT * FROM users
WHERE is_premium = 1
AND is_name = 0
AND is_customer = 0
)
SELECT *
FROM D
WHERE AGE = (SELECT MAX(AGE) FROM D)
ORDER BY ID
LIMIT 1
Assuming you have a primary key column called id, just move the query in a sub-query:
SELECT *
FROM users
WHERE id = (
SELECT id
FROM users
WHERE is_premium = 1 AND is_name = 0 AND is_customer = 0
ORDER BY age DESC
LIMIT 1
)
suppose you will have multiple users with same max() age
select * from users t1
inner join (
select max(age) maxage from users
where is_premium=1 and is_name=0 and is_customer=0) t2
on t2.maxage = t1.age
where is_premium=1 and is_name=0 and is_customer=0
or if you don't want to repeat your conditions.
select * from users t1
inner join(
select
(select max(t.age) from users t where t.id = t2.id) as maxage,
t2.id
from users t2
where is_premium=1 and is_name=0 and is_customer=0) t3 on t3.id = t1.id
How can I set a column name for the output from bellow query ?
select
(select count(*) from t_table1 id = 1)
+
(select count(*) from t_table2 id = 1)
+
(select count(*) from t_table3 id = 1)
Use as:
select ( (select count(*) from t_table1 where id = 1) +
(select count(*) from t_table2 where id = 1) +
(select count(*) from t_table3 where id = 1)
) as col
Notice that I put the entire expression in parentheses. This is not required, but it makes the code more readable. I also fixed the subqueries.
If you want to run this multiple times, then a correlated subquery makes it easier to manage the ids:
select ( (select count(*) from t_table1 t where t.id = x.id) +
(select count(*) from t_table2 t where t.id = x.id) +
(select count(*) from t_table3 t where t.id = x.id)
) as col
from (select 1 as id) x;
Then, to modify the query, you only need to change the value in one place.
use as Keyword
select (select count(*) from t_table1 id = 1)+
(select count(*) from t_table2 id = 1)+
(select count(*) from t_table3 id = 1) as result
select sum(count_tab) as col_name from(
(select count(*) as count_tab from t_table1 id = 1)
union all
(select count(*) from t_table2 id = 1)
union all
(select count(*) from t_table3 id = 1))
Using Microsoft Access. Is it possible to sort the ORDER BY column as Descending?
SELECT * FROM
(
SELECT table1.* FROM table1 ORDER BY table1.field1
) DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT table2.* FROM table2 ORDER BY table2.field1
) DUMMY_ALIAS2
Yes - just add desc after the field name:
SELECT * FROM
(
SELECT table1.* FROM table1 ORDER BY table1.field1 DESC
) DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT table2.* FROM table2 ORDER BY table2.field1 DESC
) DUMMY_ALIAS2
I'm trying to do an subquery with SUM() and LIMIT. This works fine with the following code:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = '1'
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1
But I want to do it of course dynamically and with the current row ID.
I changed the Query to the following:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
This will give the following error:
Unknown column 'p.id' in 'where clause'
Any ideas how to make it working?
Unfortunately, MySQL limits the scope of table aliases. Oracle is another database that does this.
You can phrase your query as a complicated join:
select t1.id, sum(t2.number)
from t1 p join
t2
on p.id = t2.u_id
where 30 >= (select count(*)
from t2 t22
where t22.u_id = t2.u_id and
t22.time <= t2.time
)
group by t1.id;
Or you can do this with variables:
select p.id, sum(number)
from t1 p join
(select t2.*,
#rn := if(#u = t2.u_id, #rn + 1, if((#u := t2.u_id) is not null, 1, 0)) as rn
from t2
(select #u := 0, #rn := 0) vars
order by t2.u_d, time
) t2
on p.id = t2.u_id
where rn <= 30
group by p.id;
why not just change p.id to t1.id? I'm pretty sure it's because you are aliasing t1 in the first select, and it isn't defined in the subquery. Try an inner join instead.
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
INNER JOIN t1 p
on u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
Try this:
SELECT id, temp2.sum_number as test
FROM t1 p
INNER JOIN
(
SELECT SUM(number) as sum_number, temp.u_id
FROM (
SELECT number, u_id
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS temp2 ON temp2.u_id = p.id
I moved subqueries in the join part, so i can access to p.id in the subquery.
I have fairly complicated join query from which I want to select a few rows around a result with a certain id.
The query currently looks something like this:
WITH results AS
(
SELECT t1.id, t1.position, t1.points, t2.name
ROW_NUMBER() OVER(ORDER BY t1.position ASC, t1.points DESC) AS rn
FROM Table1 t1
JOIN Table2 t2 ON t1.id = t2.Table1id
/* Several more joins here, some of which limit the result set */
)
SELECT * FROM results
WHERE rn < ( SELECT rn+3 FROM results WHERE id = #someid )
AND rn > ( SELECT rn-3 FROM results WHERE id = #someid )
Is there a better way to solve this? Most of all I'm worried about performance with these multiple calls to a possibly huge CTE.
The query is run on a SQL 2008 server.
Maybe pull the joins out of the CTE.
That way the query optimizer has a chance filter out rows before processing the joins.
WITH results AS
(
SELECT t1.id, t1.position, t1.points
, ROW_NUMBER() OVER(ORDER BY t1.position ASC, t1.points DESC) AS rn
FROM Table1 t1
)
SELECT results.id, results.position, results.points, t2.name
FROM results
JOIN Table2 t2 ON t2.id = results.Table1id
/* Several more joins here */
WHERE rn < ( SELECT rn+3 FROM results WHERE id = #someid )
AND rn > ( SELECT rn-3 FROM results WHERE id = #someid )
You could use another cte to help form the filter:
WITH results AS (
SELECT
t1.id
, t1.position
, t1.points
, t2.name
, ROW_NUMBER() OVER (ORDER BY t1.POSITION ASC, t1.points DESC) AS rn
FROM Table1 t1
JOIN Table2 t2
ON t1.id = t2.Table1id
/* Several more joins here, some of which limit the result set */
),
filter AS (
SELECT
rn
FROM results
WHERE id = #someid
)
SELECT
*
FROM results
WHERE rn < ( SELECT rn + 3 FROM filter )
AND rn > ( SELECT rn - 3 FROM filter )