I have a table with this structure:
id int
min int
max int
I want to order it ascendently and select the max of the first row, and the min of the second one.
So I did this query, and before I get the values that I need:
select min, max
from mytable
order by min asc
limit 2;
Also I tried this:
select cm_max
from mytable
order by cm_min
limit 1
union
select cm_min
from mytable
order by cm_min
limit 1,1;
But does not work...
There is any way to select only the fields I'll use?
If you want your values to be returned in one row you can do
SELECT MIN(CASE WHEN rnum = 1 THEN cm_max END) cm_max,
MIN(CASE WHEN rnum = 2 THEN cm_min END) cm_min
FROM
(
SELECT id, cm_min, cm_max, #n := #n + 1 rnum
FROM medidas, (SELECT #n := 0) n
ORDER BY cm_min
LIMIT 2
) q
What it does it gets two records with your order condition and assigns a row number to each row in the inner select. Then in the outer select we pivot whose values using CASE and row numbers.
or
SELECT q1.cm_max, q2.cm_min
FROM
(
SELECT id, cm_min, cm_max
FROM medidas
ORDER BY cm_min
LIMIT 1
) q1 CROSS JOIN
(
SELECT id, cm_min, cm_max
FROM medidas
ORDER BY cm_min
LIMIT 1, 1
) q2
In this query we grab two records of interest in sub queries and use CROSS JOIN to join two records and output needed values.
Here is SQLFiddle demo for both queries
Change your limit to 1,1 to select just the 2nd record from that set:
select cm_max as 'value'
from medidas
order by cm_min
limit 1
union
select cm_min as 'value'
from medidas
order by cm_min
limit 1,1;
Not sure if MySQL will complain about mis-matching field names, so aliases may or may not be needed.
Related
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
I have the following select in my mysql database:
select t.col1, t.THE_DATE, (select ?? as PREVIOUS_DATE)
from DUMMY_TABLE t
order by date
What I am trying to achieve is have the 'PREVIOUS_DATE' contain the value of the previous row's 'THE_DATE' column if there is one.
So if DUMMY_TABLE has the data :
col1 THE_DATE
x 10-01-2010
x 10-01-2012
x 10-01-2009
my select should return
col1 THE_DATE PREVIOUS_DATE
x 10-01-2009
x 10-01-2010 10-01-2009
x 10-01-2012 10-01-2010
You need order by clause in subquery with limit clause :
select t.col1, t.the_date,
( select t1.the_date
from dummy_table t1
where t1.col = t.col and
t1.the_date < t.the_date
order by t1.the_date desc
limit 1
) as PREVIOUS_DATE
from dummy_table t
order by the_date;
I would like to get values without the smallest and the biggest ones, so without entry with 2 and 29 in column NumberOfRepeating.
My query is:
SELECT Note, COUNT(*) as 'NumberOfRepeating'
WHERE COUNT(*) <> MAX(COUNT(*))AND COUNT(*) <> MIN(COUNT(*))
FROM Note GROUP BY Note;
SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
HAVING count(*) <
(
SELECT max(t.maxi)
FROM (select
Note, COUNT(Note) maxi FROM Notes
GROUP BY Note
) as t
)
AND
count(*) >
(
SELECT min(t.min)
FROM (select
Note, COUNT(Note) min FROM Notes
GROUP BY Note
) as t
)
try this code.
One method would use order by and limit, twice:
select t.*
from (select t.*
from t
order by NumberOfRepeating asc
limit 99999999 offset 1
) t
order by NumberOfRepeating desc
limit 99999999 offset 1;
Try this code,
Select * from Note where NumberOfRepeating < (select MAX(NumberOfRepeating) from Note ) AND NumberOfRepeating > (select MIN(NumberOfRepeating) from Note );
Here in the code, as in your table Note is the name of the table, and NumberOfRepeating is the column name, as in your table.
Try this. It should work
SELECT *
FROM ( SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
ORDER BY NumberOfRepeating DESC
LIMIT 1, 2147483647
) T1
ORDER BY T1.NumberOfRepeating
LIMIT 1, 2147483647
This question already has answers here:
How to get next/previous record in MySQL?
(23 answers)
Closed 4 years ago.
I have the following table, named Example:
id(int 11) //not autoincriment
value (varchar 100)
It has the following rows of data:
0 100
2 150
3 200
6 250
7 300
Note that id values are not contiguous.
I've written this SQL so far:
SELECT * FROM Example WHERE id = 3
However, I don't know how to get the value of previous id and value of the next id...
Please help me get previous value and next value if id = 3 ?
P.S.: in my example it will be: previous - 150, next - 250.
Select the next row below:
SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1
Select the next row above:
SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1
Select both in one query, e.g. use UNION:
(SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1)
UNION
(SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1)
That what you mean?
A solution would be to use temporary variables:
select
#prev as previous,
e.id,
#prev := e.value as current
from
(
select
#prev := null
) as i,
example as e
order by
e.id
To get the "next" value, repeat the procedure. Here is an example:
select
id, previous, current, next
from
(
select
#next as next,
#next := current as current,
previous,
id
from
(
select #next := null
) as init,
(
select
#prev as previous,
#prev := e.value as current,
e.id
from
(
select #prev := null
) as init,
example as e
order by e.id
) as a
order by
a.id desc
) as b
order by
id
Check the example on SQL Fiddle
May be overkill, but it may help you
please try this sqlFiddle
SELECT value,
(SELECT value FROM example e2
WHERE e2.value < e1.value
ORDER BY value DESC LIMIT 1) as previous_value,
(SELECT value FROM example e3
WHERE e3.value > e1.value
ORDER BY value ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3
Edit: OP mentioned to grab value of previous id and value of next id in one of the comments so the code is here SQLFiddle
SELECT value,
(SELECT value FROM example e2
WHERE e2.id < e1.id
ORDER BY id DESC LIMIT 1) as previous_value,
(SELECT value FROM example e3
WHERE e3.id > e1.id
ORDER BY id ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3
SELECT *,
(SELECT value FROM example e1 WHERE e1.id < e.id ORDER BY id DESC LIMIT 1 OFFSET 0) as prev_value,
(SELECT value FROM example e2 WHERE e2.id > e.id ORDER BY id ASC LIMIT 1 OFFSET 0) as next_value
FROM example e
WHERE id=3;
And you can place your own offset after OFFSET keyword if you want to select records with higher offsets for next and previous values from the selected record.
Here's my solution may suit you:
SELECT * FROM Example
WHERE id IN (
(SELECT MIN(id) FROM Example WHERE id > 3),(SELECT MAX(id) FROM Example WHERE id < 3)
)
Demo: http://sqlfiddle.com/#!9/36c1d/2
A possible solution if you need it all in one row
SELECT t.id, t.value, prev_id, p.value prev_value, next_id, n.value next_value
FROM
(
SELECT t.id, t.value,
(
SELECT id
FROM table1
WHERE id < t.id
ORDER BY id DESC
LIMIT 1
) prev_id,
(
SELECT id
FROM table1
WHERE id > t.id
ORDER BY id
LIMIT 1
) next_id
FROM table1 t
WHERE t.id = 3
) t LEFT JOIN table1 p
ON t.prev_id = p.id LEFT JOIN table1 n
ON t.next_id = n.id
Sample output:
| ID | VALUE | PREV_ID | PREV_VALUE | NEXT_ID | NEXT_VALUE |
|----|-------|---------|------------|---------|------------|
| 3 | 200 | 2 | 150 | 4 | 250 |
Here is SQLFiddle demo
This query uses a user defined variable to calculate the distance from the target id, and a series of wrapper queries to get the results you want. Only one pass is made over the table, so it should perform well.
select * from (
select id, value from (
select *, (#x := ifnull(#x, 0) + if(id > 3, -1, 1)) row from (
select * from mytable order by id
) x
) y
order by row desc
limit 3
) z
order by id
See an SQLFiddle
If you don't care about the final row order you can omit the outer-most wrapper query.
If you do not have an ID this has worked for me.
Next:
SELECT * FROM table_name
WHERE column_name > current_column_data
ORDER BY column_name ASC
LIMIT 1
Previous:
SELECT * FROM table_name
WHERE column_name < current_column_data
ORDER BY column_name DESC
LIMIT 1
I use this for a membership list where the search is on the last name of the member. As long as you have the data from the current record it works fine.
Lets say I have a table with 20 entries. They are sorted by date (date is a column name >_>) in descending order. How would I go about selecting ONLY the newest entry and the 15th oldest entry?
I am getting all 15 results by doing the following query
SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date DESC LIMIT 15;
Use:
SELECT x.*
FROM (SELECT a.*,
#rownum := #rownum + 1 AS rank
FROM mytable a
JOIN (SELECT #rownum := 0) r
WHERE a.col1 = "zzz"
ORDER BY a.date DESC) x
WHERE x.rank IN (1, 15)
you may need to use UNION of two SELECTs
(SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date LIMIT 1, 15)
UNION
(SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date DESC LIMIT 1)
UPDATE:
added parenthesis