SELECT * FROM table ORDER BY id ASC
Will output the full table:
id name weight
-- ---- ------
1 XXL 450
2 L 20
3 XL 30
4 XXL 875
5 S 2
Ordering by the weight and limiting to 3:
SELECT * FROM table ORDER BY weight DESC LIMIT 3
Will output:
id name weight
-- ---- ------
4 XXL 875
1 XXL 450
3 XL 30
I want to select all the rows that were not selected in the last query, as such:
id name weight
-- ---- ------
2 L 20
5 S 2
SELECT T.* FROM (
SELECT * FROM table ORDER BY weight DESC LIMIT 10 OFFSET 3
) AS T ORDER BY T.id
The inner query order the rows by weight and crop the results starting from the 4th row to the 13th. The outer query order the partial result by id.
I would just do:
select t.*
from t
where id not in (select id from t order by weight desc limit 3);
or:
select t.*
from t left join
(select id from t order by weight desc limit 3) tt
on t.id = tt.id
where tt.id is null;
However, you need to be very careful about what happens when two rows have the same weight. So, I would recommend these two queries:
select id
from t
order by weight desc, id
limit 3
select t.*
from t left join
(select id from t order by weight desc, id limit 3) tt
on t.id = tt.id
where tt.id is null;
Related
So i get 10 results from my first select and 1 from the other one after union like this:
(SELECT a.*,
b.*
FROM all a,
names b
WHERE b.name_id = a.name_id
ORDER BY name_id DESC
LIMIT 10)
UNION
(SELECT a.*,
b.*
FROM all a,
names b
WHERE b.name_id = a.name_id
ORDER BY request_id ASC
LIMIT 1)
i would like to get the result of the second select as the second last result like this
********
name_id 100
name_id 99
name_id 98
name_id 97
name_id 96
name_id 95
name_id 94
name_id 93
name_id 92
name_id 1 <- second select result as second last result
name_id 91
********
Can someone help pls?
Synthesize a row number column for the query as it stands and shuffle positions as needed.
SELECT x.name
, x.name_id
FROM (
SELECT #rownum:=#rownum + 1 as row_number,
t.name,
t.name_id
FROM (
-- original query from the question starts here
(SELECT b.name,
a.name_id
FROM allx a,
names b
WHERE b.name_id = a.name_id
ORDER BY name_id DESC
LIMIT 10)
UNION
(SELECT b.name,
a.name_id
FROM allx a,
names b
WHERE b.name_id = a.name_id
ORDER BY request_id ASC
LIMIT 1)
) t,
(SELECT #rownum := 0) r
) x
ORDER BY CASE row_number
WHEN 10 THEN 11
WHEN 11 THEN 10
ELSE row_number
END
;
(Note that the query has been sightly modified to avoid syntax errors / support the demo: table all has been named allx, explicit projections of the union's subqueries).
That gets complicated quickly thus next to ad hoc reporting it is preferable to synthesize an attribute in the subqueries of the union that reflects a global order.
Demo here (SQL fiddle)
Credits
Row number synthesizing taken from this SO answer
Interesting question given
+----+--------+
| id | sname |
+----+--------+
| 1 | sname1 |
| 2 | sname2 |
| 3 | sname3 |
| 4 | sname4 |
| 5 | sname5 |
| 6 | sname6 |
+----+--------+
6 rows in set (0.001 sec)
(select id,sname,#r:=#r+1 rn
from users
cross join(select #r:=0) r
order by sname desc limit 3
)
union
(
select u.id,u.sname,
#r:=#r - .9
from users u
left join (select id from users order by sname desc limit 3) u1 on u1.id = u.id
where u1.id is null
order by u.id asc limit 0,1
)
order by rn;
Where a variable is used to calculate a row number in the first sub query, since this variable is not reset in the second query a simple piece of arithmetic works out where to position the second sub query result. Note the second sub query uses a left join to check that the result has not already appeared in the first sub query,
I would suggest union all and three selects:
SELECT an.*
FROM ((SELECT a.*, n.*, 1 as ord
FROM all a JOIN
names n
ON n.name_id = a.name_id
ORDER BY n.name_id DESC
LIMIT 9
) UNION ALL
(SELECT a.*, n.*, 3 as ord
FROM all a JOIN
names n
ON n.name_id = a.name_id
ORDER BY n.name_id DESC
LIMIT 9 OFFSET 9
) UNION ALL
(SELECT a.*, b.*
FROM all a JOIN
names n
WHERE n.name_id = a.name_id
ORDER BY request_id ASC
LIMIT 1
)
) an
ORDER BY ord, name_id;
Id | Price
----------------
1 | 10
2 | 20
3 | 40
4 | 10
I need to select ids where first occurrence of summation of price is greater than or equal 55 matching from the bottom. At this case --
I will have 4,3,2 ids selected.
Well, this is kinda tricky for MySQL since it doesn't support any window fuctions and becuase you want to include the first occurrence as well. You can try this:
SELECT * FROM (
SELECT t.id,
(SELECT sum(s.price) FROM YourTable s
WHERE s.id <= t.id) as cuml_sum
FROM YourTable t) ss
WHERE ss.cuml_sum < 55
--Will select all the record will the sum < 55
UNION ALL
SELECT * FROM (
SELECT t.id,
(SELECT sum(s.price) FROM YourTable s
WHERE s.id <= t.id) as cuml_sum
FROM YourTable t) tt
WHERE tt.cuml_sum >= 55
ORDER BY tt.cuml_sum
LIMIT 1
--Will select the first record that have sum >= 55
I have a MySQL table
discount_vouchers
------------------
id
email
test_id
My goal is to list all vouchers that appears more than once with a given email and a given test_id from the GROUP BY:
GROUP BY email, test_id
HAVING count(*) >1
How to get read of this group by?
Here is an example:
discount_vouchers
------------------
1 1#test.com 20
2 1#test.com 10
3 1#test.com 20
4 2#test.com 30
I would like to have as a result:
id email test_id count
1 1#test.com 20 2
2 1#test.com 10 1
3 1#test.com 20 2
4 2#test.com 30 2
Try something like the following
SELECT C2, counter from
(SELECT C2, COUNT(*) as counter FROM test.mytable
GROUP BY C2) as aggregation
WHERE counter > 1
Without using group by, you can do something like
SELECT a.* ,
(SELECT count(*) FROM discount_vouchers b
WHERE a.email = b.email AND a.test_id = b.test_id) as count
FROM discount_vouchers a
How about this?
Aggregate using a subquery, and use its results in order to enrich the actual table:
SELECT `discount_vouchers`.*, `counts`.`count`
FROM `discount_vouchers`
INNER JOIN (SELECT `email`, `test_id`, Count(*) AS 'count'
FROM `discount_vouchers`) AS `counts`
ON `discount_vouchers`.`email` = `counts`.`email`
AND `discount_vouchers`.`test_id` = `counts`.`test_id`;
I tried asking question before, but it's hard to ask in specific without right terminology I am not quite familiar with. So here is an example
Take this query for example:
(
SELECT *
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
)
UNION ALL
(
SELECT c.*
FROM comments c JOIN
(
SELECT id
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
) p ON c.parent_id = p.id
LIMIT 5
)
id parent_id depth title
1 0 0 Title 1
2 0 0 Title 2
3 1 1 Title 3
4 1 1 Title 4
5 1 1 Title 5
6 1 1 Title 6
7 1 1 Title 7
I get two depth 0 rows and in join I get 5 child elements of those two returned queries as well. What I would like to get is to get 5 child elements of each of those two queries, total of 10 rows (of depth 1). For example:
id parent_id depth title
1 0 0 Title 1
2 0 0 Title 2
3 1 1 Title 3
4 1 1 Title 4
5 1 1 Title 5
6 1 1 Title 6
7 1 1 Title 7
8 2 1 Title 8
9 2 1 Title 9
10 2 1 Title 10
11 2 1 Title 11
12 2 1 Title 12
Is that even possible with adjacency list and a requirement to return everything as union (flat)?
edit:
Thanks to Bill Karwin's answer, I got it working now. I wonder still if there is a shorter way to write this. I have 6 (0-5) depth levels, so my query is rather long (and probably not optimal). Here is what it looks like for three levels (you can imagine what the full one looks like).
-- DEPTH LEVEL 0
(
SELECT * FROM (
SELECT *, 1 as _rn, #parent:=0
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
) as D0
)
union all
-- DEPTH LEVEL 1
(
SELECT *
FROM (
SELECT c.*, #row:=IF(#parent=c.comment_id,#row+1,1) AS _rn, #parent:=c.comment_id
FROM (SELECT #parent:=null) AS _init
STRAIGHT_JOIN comments c
INNER JOIN
(
SELECT id
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
) p ON c.comment_id = p.id
) AS _ranked
WHERE _ranked._rn <= 5
)
union all
-- DEPTH LEVEL 2
(
SELECT *
FROM (
SELECT c.*, #row:=IF(#parent=c.comment_id,#row+1,1) AS _rn, #parent:=c.comment_id
FROM (SELECT #parent:=null) AS _init
STRAIGHT_JOIN comments c
INNER JOIN
(
(
SELECT *
FROM (
SELECT c.*, #row:=IF(#parent=c.comment_id,#row+1,1) AS _rn, #parent:=c.comment_id
FROM (SELECT #parent:=null) AS _init
STRAIGHT_JOIN comments c
INNER JOIN
(
SELECT id
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
) p ON c.comment_id = p.id
) AS _ranked
WHERE _ranked._rn <= 2
)
) p ON c.comment_id = p.id
) AS _ranked
WHERE _ranked._rn <= 2
)
You can't do this with LIMIT, because LIMIT is applied after the result set is completely finished, after all joining, grouping, sorting, etc.
You're using a variation of the greatest-n-per-group type of query. It's tricky to do this in MySQL because MySQL doesn't support the ROW_NUMBER() window function supported by many other SQL databases.
Here's a workaround for MySQL, in which user-defined variables can take the place of partitioned row numbers:
SELECT *
FROM (
SELECT c.*, #row:=IF(#parent=c.parent_id,#row+1,1) AS _rn, #parent:=c.parent_id
FROM (SELECT #parent:=null) AS _init
STRAIGHT_JOIN comments c
INNER JOIN
(
SELECT id
FROM comments
WHERE depth = 0
ORDER BY id DESC
LIMIT 2
) p ON c.parent_id = p.id
) AS _ranked
WHERE _ranked._rn <= 5
I have the following table:
ID Category_ID Score Name
1 1 60 Name_1
2 1 50 Name_2
3 2 40 Name_3
4 3 30 Name_4
5 4 10 Name_5
lets say I run the following query:
SELECT * from table ORDER BY Score DESC LIMIT 0, 2
that will bring me:
ID Category_ID Score Name
1 1 60 Name_1
2 1 50 Name_2
How can I avoid having repeated Category_ID (as much as possible) in my results but having as 1st condition the ORDER BY Score. For example, how can I get the following instead:
ID Category_ID Score Name
1 1 60 Name_1
3 2 40 Name_3 <-- Following higher score with different Category_ID
and for
SELECT * from table ORDER BY Score DESC LIMIT 1, 2 the expected results are:
ID Category_ID Score Name
2 1 50 Name_2
4 3 30 Name_4
SELECT * from table ORDER BY Score DESC LIMIT 2, 2
the expected results are:
ID Category_ID Score Name
5 4 10 Name_5
Thank you!
You need to select only the ids that you want. This will require a join back to the original table. This version gives the result for the minimum id:
select t.*
from t join
(select category_id, min(id) as minid
from t
group by category_id
) tsum
on t.id = tsum.minid
order by max_score
limit 0, 2
If you want the maximum score, instead:
select t.*
from t join
(select category_id, max(score) as maxscore
from t
group by category_id
) tsum
on t.category_id = tsum.category_id and
t.score = tsum.maxscore
order by max_score
limit 0, 2
Of course, this assumes that the max score only appears on one record.