selecting multiple max values - mysql

i have a table like this on a mysql database:
id | item
-----------
1 | 2
2 | 2
3 | 4
4 | 5
5 | 8
6 | 8
7 | 8
i want the result to be 3 record with the highest Item value
select max(item) returns only 1 value
how can i select multiple max values?
thank you

You can use a derived table to get the maximum value and join it back to the original table to see all rows corresponding to it.
select t.id, t.item
from tablename t
join (select max(item) as mxitem from tablename) x
on x.mxitem = t.item
Edit:
select t.co_travelers_id, t.booking_id, t.accounts_id
from a_co_travelers t
join (select accounts_id, max(booking_id) as mxitem
from a_co_travelers
group by accounts_id) x
on x.mxitem = t.booking_id and t.accounts_id = x.accounts_id

If you use an 'aggregate function' without GROUP BY only one row will be returned.
You may use GROUP BY , with aggregate functions.
Here is SQLFiddle Demo
SELECT id,max(item) AS item
FROM table_name
GROUP BY id
ORDER BY item DESC
LIMIT 3
Hope this helps.

There is the graphical explanation.
There is script mysql (low abstraction level, no inner join or sth)
select * from ocena, uczen where ocena.ocena = (SELECT MAX(ocena.ocena) FROM ocena WHERE ocena.przedmiot_id="4" and ocena.uczen_id="1") and ocena.uczen_id=uczen.id and ocena.przedmiot_id="4" and uczen_id="1"

Related

MySQL select - If a column value is redundant, only show the newest by timestamp

I have a table like this:
timesent |nr | value
2018-10-31 05:23:06 | 4 | Value 3
2018-10-31 05:20:19 | 4 | Value 2
2018-10-31 05:19:35 | 4 | Value 1
2018-10-31 04:55:56 | 3 | Value 2
2018-10-31 03:05:15 | 3 | Value 1
2018-10-31 01:31:49 | 2 | Value 1
2018-10-30 04:11:16 | 1 | Value 1
At the moment, my select looks like this:
SELECT * FROM values WHERE ORDER BY timesent DESC
I want to do an sql-select statement which gives me back only the most recent value of each "nr".
My skills are not good enough to translate that into a sql-statement. I donĀ“t even know what I should google for.
Values is a Reserved Keyword in MySQL. Consider changing your table name to something else; otherwise you will have to use backticks around it
There are various ways to achieve the result for your problem. One way is to do a "Self-Left-Join" on nr (field on which you want to get the maximum timesent value row only).
SELECT v1.*
FROM `values` AS v1
LEFT JOIN `values` AS v2
ON v1.nr = v2.nr AND
v1.timesent < v2.timesent
WHERE v2.nr IS NULL
For MySQL version >= 8.0.2, you can use Window Functions. We will determine Row_Number() for each row over a partition of nr, with timesent in Descending order (Highest timesent value will have row number = 1). Then, use this result-set in a Derived Table and consider only those rows, where row number is equal to 1.
SELECT dt.timesent,
dt.nr,
dt.value
FROM
(
SELECT v.timesent, v.nr, v.value,
ROW_NUMBER() OVER (PARTITION BY v.nr
ORDER BY v.timesent DESC) AS row_num
FROM `values` AS v
) AS dt
WHERE dt.row_num = 1
Yet, another approach is to get the maximum value of timesent for a nr group in a Derived Table. Now join this result-set to the main table, so that only the rows corresponding to max value appear:
SELECT v.timesent,
v.nr,
v.value
FROM
`values` AS v
JOIN
(
SELECT nr, MAX(timesent) AS max_timesent
FROM `values`
GROUP BY nr
) AS dt ON dt.nr = v.nr AND
dt.max_timesent = v.timesent

Grab the first row that causes the sum of the previous rows to be greater that 10

I am having an issue that I can't seem to wrap my head around when it comes to creating an effective SQL.
Below is the mysql setup:
id | countValue | name
1 | 1 | b
2 | 1 | b
3 | 4 | b
4 | 6 | b
5 | 1 | b
What I am looking to do is grab the earliest row that the sum(countValue) of the previous rows (ORDER BY id DESC) become greater than 10
So in this case it would return: 3
It would return 3 because:
5.countValue + 4.countValue + 3.countValue = 12
So it would return id=3
My initial try:
SELECT id FROM user WHERE sum(countValue) > 3 ORDER by id DESC
Then I changed to:
SELECT id From users WHERE HAVING SUM(countValue) > 10 ORDER BY id DESC
The second one will only return the id if the individual countValue has more than 10 in it. Where I need the sum of the previous values which is why I am stuck.
Hope this makes sense and would love any help you guys can offer.
What you want is a cumulative or running sum. In MySQL, the best way to do this uses variables:
select u.*
from (select u.*, (#s := #s + countValue) as runningCV
from users u cross join
(select #s := 0) params
order by u.id desc
) u
where runningCV - countValue <= 10 and runningCV > 10;
The variable #s is used to calculate the cumulative sum. The outer where clause returns the first value that crosses the "10" threshold.
You can also do this with a correlated subquery. Unless your data is small, though, that will be expensive.

MySQL select query with AND condition on same columns of same table

I have a table like this
itemid | propertyname | propertyvalue
___________|______________|_______________
1 | point | 12
1 | age | 10
2 | point | 15
2 | age | 11
3 | point | 9
3 | age | 10
4 | point | 13
4 | age | 11
I need a query to select all items where age greater than 10 and point less than 12.
I tried
`select itemid from table where (propertyname="point" and propertyvalue < 12)
and (propertyname="age" and propertyvalue >10)`
It gives no results. How can I make it work?
you can use an inner join
SELECT
a.itemid
FROM
yourTable a
INNER JOIN
yourTable b
ON
a.itemid=b.itemid
AND a.propertyname='point'
AND b.propertyname='age'
WHERE
a.propertyvalue<12
AND b.propertyvalue>10
ok so in table a youre lookin for all items with the name point and a value smaller 12 and in table b youre looking for all items with the name age and a value greater 10. Then you only have to look for items, which are in both tables. For this you connect the two tables over the itemid. To connect tables you use the join. Hope this will help you to understand. If not ask again :)
To join a table to itself in the same query you can include the table twice in the FROM clause, giving it a different alias each time. Then you simply proceed with building your query as if you were dealing with two separate tables that just happen to contain exactly the same data.
In the query below the table example is aliased as a and b:
SELECT a.itemid
FROM example a, example b
WHERE a.itemid = b.itemid
AND a.propertyname = 'point'
AND a.propertyvalue < 12
AND b.propertyname = 'age'
AND b.propertyname > 10
Try It:
SELECT itemid FROM test_table WHERE propertyname="point" AND propertyvalue < 12 AND itemid IN(SELECT itemid FROM test_table WHERE propertyname="age" AND propertyvalue >10)
http://sqlfiddle.com/#!9/4eafc6/1
PLs Try this
select itemid from table where (propertyname="point" and propertyvalue < 12)
or (propertyname="age" and propertyvalue >10);
Here's one idea...
SELECT item_id
, MAX(CASE WHEN propertyname = 'point' THEN propertyvalue END point
, MAX(CASE WHEN propertyname = 'age' THEN propertyvalue END age
FROM a_table
GROUP
BY item_id
HAVING age+0 > 10
AND point+0 < 12;
You can use an inner join. Meaning, it's like you're going to work with 2 tables: the first one you're going to select the name="age" and val>10, and the second one is where you're going to select name="point" and val<12.
It's like you're creating an instance of your table that doesn't really exist. It's just going to help you extract the data you need at the same time.

MYSQL select from table where field is in the field

UPDATED
id | id_list
1 | 2,3,5,7
2 | 1,4,5,6
3 | 1,4,6,7
4 | 2,3,5,8
5 | 1,2,4,8
6 | 2,3,7,8
7 | 1,3,6,9
8 | 4,5,6,9
9 | 7,8
let's say I'm up to the content of id=1
I wanted to select all the rows where id is in id_list of id=1 PLUS the row where id=1
so the result would be
rows with id = 1,2,3,5,7
How to do this query guys?
You can also use a self join
Using IN()
select * from atable a
join atable b on (a.id = b.id )
where 1 IN (a.id_list) or b.id =1
Fiddle with IN()
Using FIND_IN_SET()
select * from atable a
join atable b on (a.id = b.id )
where FIND_IN_SET('1', a.id_list) or b.id =1
Fiddle with FIND_IN_SET()
Using UNION ALL
select * from atable
where id =1
UNION ALL
select * from atable
where 1 IN (id_list)
Fiddle with UNION ALL
Your database design is broken; id_list should be represented as a join table instead of as a string. However, to solve your immediate problem:
select * from table where id=1
or id_list like '1%'
or id_list like '%,1,%'
or id_list like '%,1'
Adjust as needed for PreparedStatement. You have to provide all three cases because if you just did
or id_list like '%1%'
and id_list contained the value 11, you'd get an incorrect match
Try this (see SQL-Fiddle):
SELECT * FROM tbl
WHERE id = 1
OR INSTR((SELECT id_list FROM tbl WHERE id = '1'), id) > 0;
Tested with MySQL 5.5.30
try this one
select *
from tbl
where id=1
or id_list like '%1%'
This appears to call for a union of two sets. The one set would be the single row whose id matches the specified value:
SELECT
id
FROM
atable
WHERE
id = #id
The other set would be the result of this self-join:
SELECT
item.id
FROM
atable AS item
INNER JOIN
atable AS list
ON
FIND_IN_SET(item.id, list.id_list)
WHERE
list.id = #id
That is, the row with the specified id is matched against every row in the table on the condition that the other row's id is found in the specified row's id_list.
You can try the complete query at SQL Fiddle.
Please note that lists aren't a very good design feature. In your situation, it might be better to use a many-to-many table as suggested by #Othman. Only I would probably use a slightly different query to get the desired output, because his doesn't include the specified row itself:
SELECT
id
FROM
manytomany
WHERE
id = #id
UNION
SELECT
linked_id
FROM
manytomany
WHERE
id = #id
;
While the entries in manytomany are assumed to be unique, the query uses the UNION DISTINCT operator because of the potential duplicates returned by the first subquery, although it is possible to move the application of DISTINCT to the first subquery only like this:
SELECT DISTINCT
id
FROM
manytomany
WHERE
id = #id
UNION ALL
SELECT
linked_id
FROM
manytomany
WHERE
id = #id
;
That first subquery could actually be rewritten simply as SELECT #id AS id, but the rewrite would only make sense if the passed value was guaranteed to be valid, i.e. that it would definitely be found in manytomany.id.
Here's a demo for the other approach too (all three variations, including the SELECT #id AS id one).
I don't have an answer for your question but I encourage you to redesign your table like this I think this called many to many relation
id | friend
1 | 2
1 | 3
1 | 5
1 | 7
2 | 1
2 | 4
2 | 5
2 | 6
3 | 1
3 | 4
3 | 6
3 | 7
And then your query will be like this
SELECT DISTINCT(friend) FROM `new` WHERE id = 1
I am assuming you are using php..
My suggestion is to grab the id_list for id 1.
Explode that id_list on the comma, and then do another mysql query to grab the remaining results for 5|3|6|8
ex) $idarray = explode(",", $result);
select * from your_table where id in ('5','3','6','8')
OPTION 2:
SELECT * FROM your_table
WHERE id = '1'
OR id IN ('\''+(SELECT REPLACE(id_list,',','\',\'') FROM your_table WHERE id = '1')+'\'')
EDIT: Oops, sorry, that should be an OR instead.

MySQL join query or sub query

I'm trying to do a query that selects mike if it isn't in the three highest bids for a keyword. Rows 4 and 7 should be selected.
So in final, if mike isn't in the three highest bids for a keyword, then select.
How do I solve this? With a sub query?
$construct = "SELECT child.* FROM `temp-advertise` child
LEFT JOIN `temp-advertise` parent on child.keyword=parent.keyword
WHERE child.name='mike'
ORDER BY child.id DESC";
id | name| keyword | bid |
1 | mike| one | 7 |
2 | tom | one | 4 |
3 | ced | one | 6 |
4 | mike| two | 1 |
5 | tom | two | 5 |
6 | har | two | 5 |
7 | mike| one | 3 |
8 | har | two | 3 |
SELECT *
FROM `temp-advertise` ta
WHERE ta.keyword = 'one'
AND ta.name = 'mike'
AND ta.bid <
(
SELECT bid
FROM `temp-advertise` tai
WHERE tai.keyword = 'one'
ORDER BY
bid DESC
LIMIT 2, 1
)
Your structure doesn't look too promising, nor your sample data. However, that said, you want to know if "Mike" was in the top 3 per keyword... and that he has 3 bids.... 2 for "one", 1 for "two". From the raw data, it looks like Mike is in 1st place and 4th place for the "one" keyword, and 4th place for "two" keyword.
This should get you what you need with SOME respect to not doing a full query of all keywords. The first innermost query is to just get keywords bid on by "mike" (hence alias "JustMike"). Then join that to the temp-advertise on ONLY THOSE keywords.
Next, by using MySQL variables, we can keep track of the rank PER KEYWORD. The trick is the ORDER BY clause needs to return them in the order that represents proper ranking. In this case, each keyword first, then within each keyword, ordered by highest bid first.
By querying the records, then using the #variables, we increase the counter, start at 1 every time the keyword changes, then preserve the keyword into the #grpKeyword variable for comparison of the next record. Once ALL bids are processed for the respective keywords, it then queries THAT result but ONLY for those bid on by "mike". These records will have whatever his rank position was.
select RankPerKeyword.*
from
( SELECT ta.*,
#grpCnt := if( #grpKeyword = ta.Keyword, #grpCnt +1, 1 ) as KWRank,
#grpKeyword := ta.Keyword as carryForward
FROM
( select distinct ta1.keyword
from `temp-advertise` ta1
where ta1.name = "mike" ) as JustMike
JOIN `temp-advertise` ta
on JustMike.Keyword = ta.Keyword,
( select #grpCnt := 0,
#grpKeyword := '' ) SqlVars
ORDER BY
ta.Keyword,
ta.Bid DESC" ) RankPerKeyword
where
RankPerKeyword.name = "mike"
(Run above to just preview the results... should show 3 records)
So, if you want to know if it was WITHIN the top 3 for a keyword you could just change to
select RankPerKeyword.keyword, MIN( RankPerKeyword.KWRank ) as BestRank
from (rest of query)
group by RankPerKeyword.Keyword
Try this:
Select ID, name, keyword from temp-advertise e
where 3 <= (select count(name) from temp-advertise
where e.keyword = keyword and bid > e.bid)
Try
SELECT .. ORDER BY bid LIMIT 3,999