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
Related
Let's say I have table like this:
some_id
date
1
2022-02-01
2
2022-02-02
3
2022-02-03
3
2022-02-04
3
2022-02-05
3
2022-02-06
I want to get the number of rows based on the id where the date was found?
I tried this but it's not working:
SELECT COUNT(id) FROM dates WHERE date = '2022-02-04'
Expected output should be 4 rows since there are 4 same id's where the 2022-02-04 was found.
This should do the job:
SELECT COUNT(*) FROM tbl
WHERE id IN (
SELECT id FROM tbl WHERE `date`='2022-02-04'
)
An exists query should do it:
SELECT id, COUNT(*)
FROM t
WHERE EXISTS (
SELECT 1
FROM t AS x
WHERE x.id = t.id
AND x.date = '2022-02-04'
)
GROUP BY id
Using exists logic we can try:
SELECT COUNT(*)
FROM dates d1
WHERE EXISTS (SELECT 1 FROM dates d2
WHERE d2.some_id = d1.some_id AND
d2.date = '2022-02-04');
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;
I've got a query returning the following:
ID | Price
---------------
1 | 20
1 | 30
1 | 15
2 | 10
2 | 12
2 | 20
3 | 1
3 | 0
3 | 0
4 | 0
4 | 0
4 | 7
I'm wondering if there's a way I can get the sum of the lowest value for each ID. So in this case it would return 25.
15+10+0+0
You can use a subquery selecting the min price for each id, then sum those values:
select sum(minprice) as overallprice
from (
select min(price) minprice
from yourtable
group by id) t
You can create a sub-query that finds the lowest price per id and take the results from that and sum them together. In pseudo-code:
select
sum(lowest_price)
from (select id, min(price) as lowest_price from prices group by id) lowest_prices
You can do a query like below
Select sum (a) from
(
Select min (price) as a from yourtable
Group by id
) t
Another approach using partition without using group by statement
select sum(price.min_price) from
(select distinct id,min(price) over(partition by id) as min_price from prices) price
Some other approaches would be to use MySQL user variables or a self left join..
MySQL user variable solution
Query
SELECT
SUM(prices.Price)
FROM (
SELECT
prices.Price
, CASE
WHEN #id != prices.id
THEN 1
ELSE 0
END AS isMinGroupValue
, (#id := prices.id)
FROM
prices
CROSS JOIN (
SELECT
#id := 0
) AS init_user_params
ORDER BY
prices.ID ASC
, prices.price ASC
) AS prices
WHERE
prices.isMinGroupValue = 1
see demo https://www.db-fiddle.com/f/nzWqMQAxd7mvq589R7WuZ8/0
Self left join solution
Query
SELECT
SUM(prices1.Price)
FROM
prices prices1
LEFT JOIN
prices prices2
ON
prices1.ID = prices2.ID
AND
prices1.price > prices2.price
WHERE
prices2.ID IS NULL
see demo https://www.db-fiddle.com/f/nzWqMQAxd7mvq589R7WuZ8/1
I would use correlation subquery :
select sum(t.price) as overallprice
from table t
where price = (select min(price) from table t1 where t1.id = t.id);
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 need to pull the name of the students who stood second positions from grade 1 to grade 12. each grade has separate databases with similar table structure
I have the following data:
Set 1
uid marks
1 10
2 20
3 17
4 17
5 20
6 20
Set 2
uid marks
1 10
2 20
3 17
4 17
5 20
6 17
7 20
I need a query which can say uid 3,4 are second in set 1 and 3,4,6 are second in set 2.
i need it in a single query because there are several set of databases
what could be the possible way?
I tried:
SELECT * FROM TBL WHERE marks ! = SELECT MAX(marks) from tbl
but it fetched all marks except the highest
Try this out:
SELECT uid, marks FROM (
SELECT uid, marks, #rank := #rank + (#prevMarks != marks) rank, #prevMarks := marks
FROM t, (SELECT #rank := 0, #prevMarks := 0) init
ORDER BY marks
) s
WHERE rank = 2
Fiddle here.
Another alternative without User Defined Variables:
SELECT t.uid, t.marks FROM t
JOIN (
SELECT DISTINCT marks FROM t
ORDER BY marks
LIMIT 1, 1
) s
ON t.marks = s.marks
Output:
| UID | MARKS |
|-----|-------|
| 3 | 17 |
| 4 | 17 |
Use LIMIT and ORDER BY
SELECT * FROM TBL ORDER BY marks DESC LIMIT 1,1
There you ordered all students by marks fro hi to low. And then limit return from second (0 is first record) and return only one record.
If need all students with second mark, the use subquery
SELECT * FROM TBL WHERE marks = (
SELECT marks FROM TBL ORDER BY marks DESC GROUP BY marks LIMIT 1,1
)
SELECT *
FROM table
WHERE mark = (
SELECT MAX(mark)
FROM table
WHERE mark <
(
SELECT MAX(mark)
FROM table
)
)
Try this
SELECT t.marks, t.uid, (
SELECT COUNT( marks ) +1
FROM tbl t1
WHERE t.marks < t1.marks
) AS rank
FROM tbl t
LIMIT 0 , 30
now you can use rank column with bit modification below
SELECT * from (
SELECT t.marks, t.uid, (
SELECT COUNT( marks ) +1
FROM tbl t1
WHERE t.marks < t1.marks
) AS rank
FROM tbl t
) alias where rank=n (2 here)