I have a MySQL problem that I can't figure out.
I run a query:
SELECT id, totalsum FROM table ORDER BY totalsum DESC
This could give me the following result:
1, 10000
4, 90000
8, 80000
3, 50000
5, 40000
++++
What is need is a code that should work something like this:
SELECT id, totalsum
FROM table ORDER BY totalsum DESC
START LISTING FROM id=8 AND CONTINUE TO THE END OF RESULT / LIMIT
Resulting in someting like this
8, 80000
3, 50000
5, 40000
++++
I can not use this query:
SELECT id, totalsum
FROM table
WHERE id>=8
ORDER BY totalsum DESC
Because the id could be both < and >.
Have tried using LIMIT AND OFFSET but that resulting in very slow speed.
Any advice pointing me in the right direction will be appreciated!
Here's a way to do it:
Assign each row a row_num based on totalsum in descending order (CTE)
Select from the above where row_num >= the row_num of id=8
create table a_table (
id int,
total int);
insert into a_table values
(1, 100000),
(4, 90000),
(8, 80000),
(3, 50000),
(5, 40000);
with cte as (
select id,
total,
row_number() over (order by total desc) as row_num
from a_table)
select *
from cte
where row_num >= (select row_num from cte where id=8);
Result:
id|total|row_num|
--+-----+-------+
8|80000| 3|
3|50000| 4|
5|40000| 5|
EDIT:
The above query may return wrong result if other rows have the same total. A comment said it well, just use the following query can do the job:
select id, total
from a_table
where total <= (select total from a_table where id=8)
order by total desc;
Related
I have following table
CREATE TABLE Table1
(`userid` varchar(11), `score` int, `type` varchar(22));
INSERT INTO Table1
(`userid`, `score`,`type`)
VALUES
(11, 2,'leader'),
(11, 6,'leader'),
(13, 6,'leader'),
(15, 4,'leader'),
(15, 4,'leader'),
(12, 1,'leader'),
(14, 1,'leader');
I need to get userid of the maximum score take user.
if the max score is the same for two or more user need to get that userid also.
I have try following query
SELECT userid, sum(score) as totalScore
FROM Table1 WHERE type = "leader" GROUP BY userid
ORDER BY totalScore DESC;
But it gets all user data, cant get the max score take the first two users id.
But I need to get only first two row of data ..
Please help me
On MySQL 8+, I suggest using the RANK() analytic function:
WITH cte AS (
SELECT userid, SUM(score) AS totalScore,
RANK() OVER (ORDER BY SUM(score) DESC) rnk
FROM Table1
WHERE type = 'leader'
GROUP BY userid
)
SELECT userid, totalScore
FROM cte
WHERE rnk = 1;
if you need just top 2 records add limit in your query :
SELECT userid, sum(score) as totalScore
FROM Table1 WHERE type = "leader" GROUP BY userid
ORDER BY totalScore DESC LIMIT 2;
I'm attempting to create an SQL query that retrieves the total_cost for every row in a table. Alongside that, I also need to collect the most dominant value for both columnA and columnB, with their respective values.
For example, with the following table contents:
cost
columnA
columnB
target
250
Foo
Bar
XYZ
200
Foo
Bar
XYZ
150
Bar
Bar
ABC
250
Foo
Bar
ABC
The result would need to be:
total_cost
columnA_dominant
columnB_dominant
columnA_value
columnB_value
850
Foo
Bar
250
400
Now I can get as far as calculating the total cost - that's no issue. I can also get the most dominant value for columnA using this answer. But after this, I'm not sure how to also get the dominant value for columnB and the values too.
This is my current SQL:
SELECT
SUM(`cost`) AS `total_cost`,
COUNT(`columnA`) AS `columnA_dominant`
FROM `table`
GROUP BY `columnA_dominant`
ORDER BY `columnA_dominant` DESC
WHERE `target` = "ABC"
UPDATE: Thanks to #Barmar for the idea of using a subquery, I managed to get the dominant values for columnA and columnB:
SELECT
-- Retrieve total cost.
SUM(`cost`) AS `total_cost`,
-- Get dominant values.
(
SELECT `columnA`
FROM `table`
GROUP BY `columnA`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnA_dominant`,
(
SELECT `columnB`
FROM `table`
GROUP BY `columnB`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnB_dominant`
FROM `table`
WHERE `target` = "XYZ"
However, I'm still having issues figuring out how to calculate the respective values.
You might get close, if we want to get percentage values we can try to add COUNT(*) at subquery to get max count by columnA and columnB then do division by total count
SELECT
SUM(cost),
(
SELECT tt.columnA
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnA_dominant,
(
SELECT tt.columnB
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnB_dominant,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnA_percentage,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnB_percentage
FROM T t1
If your MySQL version supports the window function, there is another way which reduce table scan might get better performance than a correlated subquery
SELECT SUM(cost) OVER(),
FIRST_VALUE(columnA) OVER (ORDER BY counter1 DESC) columnA_dominant,
FIRST_VALUE(columnB) OVER (ORDER BY counter2 DESC) columnB_dominant,
FIRST_VALUE(counter1) OVER (ORDER BY counter1 DESC) / COUNT(*) OVER() columnA_percentage,
FIRST_VALUE(counter2) OVER (ORDER BY counter2 DESC) / COUNT(*) OVER() columnB_percentage
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY columnA) counter1,
COUNT(*) OVER (PARTITION BY columnB) counter2
FROM T
) t1
LIMIT 1
sqlfiddle
try this query
select sum(cost) as total_cost,p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
from get_common,(
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
)p,
(select top 1 columnB,columnB_percentage
from (
select columnB,count(columnB) as count_columnB, cast(count(columnB) as float)/(select count(columnB) from get_common) as columnB_percentage
from get_common
group by columnB) t
order by count_columnB desc)q
group by p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
so if you want to get the percent and dominant value you must make their own query like this
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
then you can join with the sum query to get all value you want
hope this can help you
Let's say I have a query
SELECT *
FROM foo
ORDER BY id
And I want the 1st, 5th, 100th, 250th result, etc.
SELECT *
FROM foo
ORDER BY id
LIMIT 5, 1
Gives you the 5th. And I could run a similar query N times. But, how can I do it more elegantly in only one query?
Something like this (which doesn't work) would be amazing!
LIMIT 1, 5, 100, 250
One way would be ROW_NUMBER(MySQL 8.0):
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id) AS rn FROM foo) sub
WHERE rn IN (1, 5, 100, 250)
ORDER BY rn;
You can achieve it by using a variable for MySQL >= 5.x.x
SELECT z.*
FROM (
SELECT *, #row_number:=#row_number+1 AS row_number
FROM foo, (SELECT #row_number:=0) AS t
ORDER BY pkey
) AS z
WHERE row_number IN (1, 5, 100, 250);
Here the variable is declared as a table t. #row_number will be incremented by 1 for each row which can then be filtered using WHERE clause.
I have a PostgreSQL table like this:
CREATE TABLE foo(man_id, subgroup, power, grp)
AS VALUES
(1, 'Sub_A', 4, 'Group_A'),
(2, 'Sub_B', -1, 'Group_A'),
(3, 'Sub_A', -1, 'Group_B'),
(4, 'Sub_B', 6, 'Group_B'),
(5, 'Sub_A', 5, 'Group_A'),
(6, 'Sub_B', 1, 'Group_A'),
(7, 'Sub_A', -1, 'Group_B'),
(8, 'Sub_B', 2, 'Group_B'),
(9, 'Sub_C', 2, 'Group_B');
The power calculation works like this:
Total Power of Subgroup Sub_A in the grp Group_A is (4 + 5 ) = 9
Total Power of Subgroup Sub_B in the grp Group_A is ((-1) + 1 ) = 0
Total Power of Subgroup Sub_A in the grp Group_B is ((-1) + (-1) ) = -2
Total Power of Subgroup Sub_B in the grp Group_B is (6 + 2 ) = 8
So the power of Sub_A in the Group_A is not equal to power of Sub_A in the Group_B
So the power of Sub_B in the Group_A is not equal to power of Sub_B in the Group_B
I want to query the database and fetch the rows where, for a same subgroup name total power is not equal across all the other grp names.
What would be the recommended way to do this?
I can find the sum of total power:
SELECT sum(power) AS total_power
FROM foo
GROUP BY grp
MySQL solution will be accepted as well.
One way:
SELECT f.*
FROM (
SELECT subgroup
FROM (
SELECT subgroup, grp, sum(power) AS total_power
FROM foo
GROUP BY subgroup, grp
) sub
GROUP BY 1
HAVING min(total_power) <> max(total_power) -- can fail for NULL values;
) sg
JOIN foo f USING (subgroup);
In your example all rows qualify except for the last one with 'Sub_C'.
Closely related to your previous question:
Do all groups have equal total power for given subgroup?
Similar explanation and considerations.
db<>fiddle here
I think a way to phrase your problem is that you want to total the power for subgroup in a group, then find if a subgroup with the same name exists in another group with a different power.
The first step is to total the powers like you want:
SELECT grp, subgroup, sum(power) as power
FROM foo
GROUP BY grp, subgroup
That should give you a result like:
grp subgroup power
------- -------- -----
Group_A Sub_A 9
Group_A Sub_B 0
Group_B Sub_A -2
Group_B Sub_B 8
Group_B Sub_C 2
Once you have that, you can use a CTE to join the results with itself for the comparison to get what you want. You don't specify whether you want Sub_C to appear, if 'not existing' qualifies as having a 'different total power', then you would want to use a left join and check for nulls in alias b. The < in the join makes it so that each difference only appears once with the lower order group as grp1.
WITH totals AS (
SELECT grp, subgroup, sum(power) as power
FROM foo
GROUP BY grp, subgroup
ORDER BY grp, subgroup
)
SELECT a.subgroup,
a.grp as grp1, a.power as Power1,
b.grp as grp2, b.power as Power2
FROM totals a
INNER JOIN totals b ON b.subgroup = a.subgroup
and a.grp < b.grp
WHERE b.power <> a.power
ORDER BY a.subgroup, a.grp, b.grp
with totals as (
select grp, subgroup, sum(power) as total_power
from foo
group by grp, subgroup
)
select * from totals t1
where t1.total_power <> all (
select t2.total_power from totals t2
where t2.subgroup = t.subgroup and t2.grp <> t1.grp
)
or
with totals as (
select grp, subgroup, sum(power) as total_power
from foo
group by grp, subgroup
), matches as (
select grp, subgroup, count(*) over (partition by subgroup, total_power) as matches
)
select * from counts where matches = 1;
I would use window functions:
select f.*
from (select f.*,
min(sum_value)) over (partition by group) as min_sum_value,
max(sum_value)) over (partition by group) as max_sum_value,
from (select f.*,
sum(value) over (partition by subgroup, group) as sum_value
from foo f
) f
) f
where min_sum_value <> max_sum_value;
I'm trying to get the ID where the Upper value is less than/equal to a given value.
myTable
(`ID`, `Lower`, `Upper`)
(1, 1, 9),
(2, 10, 49),
(3, 50, 99),
(4, 100, 499),
(5, 500, 999),
(6, 1000, 4999),
(7, 5000, 9999);
I've tried:
SELECT ID
FROM myTable
WHERE Lower>=3 AND Upper<=3;
and
SELECT ID
FROM myTable
WHERE Upper<=3
ORDER BY ID DESC;
and
SELECT ID
FROM myTable
GROUP BY ID HAVING MAX(Upper)<=3
ORDER BY MAX(Upper);
and
SELECT *
FROM myTable t1
WHERE t1.Upper <= (
SELECT (MAX(t2.Upper))
FROM myTable t2
);
all of which return empty rows.
The option:
SELECT ID
FROM myTable
WHERE Upper<=10
ORDER BY ID DESC;
works where the test value is greater than 9...
Can anyone suggest a solution that might work?
The syntax on
SELECT ID
FROM myTable
WHERE Upper<=3
ORDER BY ID DESC;
Works just fine on MYSQL? double check for spelling errors or syntactical errors perhaps?
If you want to return NULL where there is no match instead of "no rows", you can try something like:
SELECT max(ID)
FROM myTable
WHERE Upper<=3;
I think I get it now - you want the id of the maximum Upper value, as long as it is less than or equal to your "test" value. Is that correct?
select id
from myTable
where Upper <= X
order by Upper desc
LIMIT 1;
So if X = 9 you would get ID: 1
If X = 10 you would also get ID: 1
If X = 163 you would get ID: 3