How to sort in a different way - mysql

There are countries in MySQL table:
id | title
1 | USA
2 | Spain
3 | Italy
4 | Canada
I need to select Italy on the top of list and other countries sorted by title below.
But 'order by' doesn't work.
(SELECT * FROM countries WHERE id = 3) UNION (SELECT * FROM countries WHERE id != 3 ORDER BY title)

First sort your data based on whether it is Italy or not, getting Italy first. Then sort based on the title.
SELECT * FROM countries
ORDER BY title='Italy' DESC, title
(The only trick you have to know -- or experiment with -- is that FALSE comes before TRUE, and hence the DESC in the code. I guess that makes sense if you convert them to 0 < 1.)

you can try this
SELECT * FROM countries
ORDER BY case when id !=3 then `title` end asc ,
case when id =3 then `title` end asc ;

SELECT * FROM countries WHERE id = 3
union
SELECT c.* FROM (SELECT * FROM countries WHERE id != 3 order by title) c

Related

Group by names desc - get last entered values for a grouped name

I have an table like that:
id | name | v (lvl)
11 | Jane | 6
12 | John | 5
13 | Jane | 6
14 | John | 5
15 | Jane | 7
16 | Jane | 5
In my autocomplete form now id like to group the names but get the last value (value with biggest id). In the example above would be
Jane | 5
I tried with combinations like distinct, group by, order by. But im always get
Jane | 6
or grouped like this and reversed:
Jane | 6
Jane | 7
Jane | 5
I would need something like this:
SELECT name,lvl FROM
(
SELECT DISTINCT name, lvl FROM pora WHERE name LIKE 'Jane' ORDER BY lvl DESC
)
GROUP BY name
EDIT: I won't get the highest lvl, i want get the lvl of the highest id, grouped by name. Thats all. My example above would be the best explanation what i like to get.
In the inner query i change the order to DESC for all and in the outer i group it by names. But i get an error for this.
EDIT 2 I finally did at my own. The correct solution (i was already close):
SELECT a.name, a.lvl FROM
(
SELECT DISTINCT name, lvl FROM pora WHERE name LIKE 'Jane' ORDER BY id DESC
)as a
GROUP BY name
LIKE without % is just =
SELECT *
FROM yourTable
WHERE name = 'Jane'
ORDER BY id DESC
LIMIT 1
But because you mention autocomplete functionality you should use:
WHERE name LIKE 'Jane%'
To have the latest, you need to have a field dateAdded which stores the date you ran the insert command.
Following which, you use MAX(dateAdded) to get the latest ID (since, as you mentioned, it may decrease as well)
UPDATE:
if ID doesn't decrease, you can always use MAX(ID)
SELECT MAX(id), v from tablename where name = 'Jane'
UPDATE:
This has been tested:
SELECT ID, v from tableName where ID = (SELECT MAX(ID) as ID from tableName where name like '%Jane%')
Try the following query (h/t #lamak)
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY name
ORDER BY [id] DESC)
FROM poro
)
SELECT *
FROM CTE
WHERE RN = 1

SQL: Group by - further attribute with largest quantity

I'm new to SQL and facing following problem:
This is my table:
name city people
-----|-----|--------|
John | A | 5 |
Ben | D | 6 |
John | A | 5 |
Ben | A | 5 |
John | B | 8 |
Ben | D | 6 |
I want to group by the name and receive associated to the name that city with the largest quantity. As a second query, instead of the largest quantity, that city with the highest sum of inhabitants.
This would be the outcome for the first query:
name city
-----|-----|
John | A |
Ben | D |
Thank you!
I don't know exactly what you mean by "to the name that city with the largest quantity". What I understood was you sum the column 'people' per couple (name, city), thus (John, A) would be 10 and (John, B) would be 8, and you take the max value to get (John, A).
In this case, you can do it this way:
SELECT
name,
city
FROM
(SELECT
name,
city,
SUM(people) AS tot
FROM table
GROUP BY name, city
ORDER BY name ASC, tot DESC) AS a
GROUP BY name ;
As for the city with the largest number of inhabitants, you just have to group by city and sum the column people and take the max:
SELECT
city,
SUM(people) AS nb_inhabitants
FROM table
GROUP BY city
ORDER BY nb_inhabitants DESC
LIMIT 1;
SELECT name, city, sum( people )
FROM `detail`
GROUP BY name
ORDER BY people ASC
LIMIT 0 , 30
I am not really understand what your are expecting ,but I guess you want to do this thing.
Description : I am group by people from there name , and got sum of the people and make them ASC order. I am not sure your are expect this thing.
You can also , group people by their city
SELECT name, city, sum( people )
FROM `detail`
GROUP BY city
ORDER BY people ASC
LIMIT 0 , 30
If this not you expect , Please , further describe question ,we will try to give some answer.
Try this, I have tried by making a table as per your sample data,
CREATE TABLE KaiTable
(
NAME VARCHAR(50)
,city CHAR(1)
,people INT
);
INSERT INTO KaiTable
VALUES
(
'John'
,'A'
,5
),
('Ben ' ,'D' ,6),
('John' ,'A' ,5),
('Ben ' ,'A' ,5) ,
('John' ,'B' ,8) ,
('Ben ' ,'D' ,6)
SELECT NAME,city
FROM
(SELECT NAME,city,SUM(people) AS PeopleSum
FROM KaiTable
GROUP BY NAME, city
ORDER BY NAME ASC, PeopleSum DESC) AS a
GROUP BY NAME DESC;
SQL Fiddle Demo

Get the max value in a specific group of rows

I have these two tables:
popular_song
song_name | rate | country_id
------------------------------
Tic Tac | 10 | 1
Titanic | 2 | 1
Love Boat | 8 | 2
Battery | 9 | 2
country
conutry_id | country
--------------------------
1 | United States
2 | Germany
What I'd like to achieve is to get the most poular song in each country, e.g.:
song_name | rate | country
--------------------------
Tic Tac | 10 | United States
Battery | 9 | Germany
I've tried this query:
SELECT MAX(rate), song_name, country
FROM popular_song ps JOIN country cnt
ON ps.country_id = cnt.country_id
GROUP BY country
But this doesn't work. I've tried looking at questions like "Order by before group by" but didn't find an answer.
Which mysql query could achieve this result?
You can use another self join to popular songs table with the max rating
SELECT ps.*,cnt.country
FROM popular_song ps
JOIN (SELECT MAX(rate) rate, country_id FROM popular_song GROUP BY country_id) t1
ON(ps.country_id = t1.country_id and ps.rate= t1.rate)
JOIN country cnt
ON ps.country_id = cnt.conutry_id
See Demo
There is a trick that you can use with substring_index() and group_concat():
SELECT MAX(rate),
substring_index(group_concat(song_name order by rate desc separator '|'), '|', 1) as song,
country
FROM popular_song ps JOIN
country cnt
ON ps.country_id = cnt.country_id
GROUP BY country;
EDIT:
If you have big tables and lots of songs per country, I would suggest the not exists approach:
select rate, song country
from popular_song ps join
country cnt
on ps.country_id = cnt.country_id
where not exists (select 1
from popular_song ps2
where ps2.country_id = ps.country_id and ps2.rate > ps.rate
);
Along with an index on popular_song(country_id, rate). I recommended the group_concat() approach because the OP already had a query with a group by, so the trick is the easiest to plug into such a query.
Here is another way I'v learned from #Gordon Linoff. Here is that question you could learn too.
SELECT ps.*,cnt.country
FROM
(SELECT popular_song.*,
#rownum:= if (#c = country_id ,#rownum+1,if(#c := country_id, 1, 1) )as row_number
FROM popular_song ,
(SELECT #c := '', #rownum:=0) r
order by country_id, rate desc) as ps
LEFT JOIN country cnt
ON ps.country_id = cnt.conutry_id
WHERE ps.row_number = 1
This is the way of implementing row_number()(Partition by ...) window function in MySql.
You can do this with EXISTS like this:
SELECT rate, song_name, cnt.country_id
FROM popular_song ps JOIN country cnt
ON ps.country_id = cnt.country_id
WHERE NOT EXISTS
(SELECT * FROM popular_song
WHERE ps.country_id = country_id AND rate > ps.rate)
It is not specified in the question whether two songs can be returned per country if their rating is the same. Above query will return several records per country if ratings are not unique at country level.

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

MySQL query by string and limit

I have a table "articles" that has a column "company" which has list of companies or an article type - crappy I know, but it's not my DB. :) Let's say there are n articles for each type. I need to select the first article (based on year, or any other criteria) that is of the type. Something like this:
select * from details where (company = 'aaa' or company = 'bbb' or ...)
I know what the types are, so they can be hardcoded. I need to limit only the first article for each type. Thanks!
EDIT
given the sample data:
id company copy issue
------------------------
1 apple 'abc' NULL
2 bmw 'abc' NULL
3 ibm 'abc' NULL
4 news 'abc' 2
5 news 'abc' 3
6 seagate 'abc' NULL
7 events 'abc' 1
8 features 'abc' 5
9 samsung 'abc' NULL
I need rows 4, 7, 8.
EDIT2
Sorry if I wasn't clear. Essentially the table contains two different types of data. One is company info, and one is article info. Basically I need to do this:
select * from articles where company = "news" order by issue limit 1;
select * from articles where company = "events" order by issue limit 1;
select * from articles where company = "features" order by issue limit 1;
but with a single query.
Something like this perhaps
select * from details d
where company in ('news', 'events', 'features')
and not exists (
select 1 from details d_
where d_.company = d.company
and d_.id < d.id -- provide your sortable criteria here
)
Example here - http://sqlfiddle.com/#!2/bb8f2/6
This query:
select t1.* from t t1
left join t t2
on t1.company = t2.company and t1.id > t2.id
where t2.id is null and t1.company in ('news', 'events', 'features')
will return:
+----+----------+------+
| ID | COMPANY | COPY |
+----+----------+------+
| 4 | news | abc |
| 7 | events | abc |
| 8 | features | abc |
+----+----------+------+
Is that what you're looking for?
Note: When you say the first article I assume the order is provided by the ID field
You can play with it here
Edit:
After your edit, the query is almost the same, just change the ordering field to issue instead of id:
select t1.* from t t1
left join t t2
on t1.company = t2.company and t1.issue > t2.issue
where t2.id is null and t1.company in ('news', 'events', 'features')
Assuming "company" and "publication_date" are columns in table "details", then something like:
select *
from details
where company in ('aaa', 'bbb', ...)
and publication_date between '2012-02-01' and '2012-03-01'
order by publication_date desc
limit 1
You are trying to do a group by.
Next you want to order by the issue column.
Then you only need the first row.
I used group concat to create a list,
then extract the first string in the ordered list group_concat(copy order by copy).
select
id,
company,
substring(
group_concat(copy order by copy),
1,
case when substring_index(group_concat(copy order by copy),',',1) > 1
then substring_index(group_concat(copy order by copy),',',1)-1
else 1 end
) as copy
from details d
where company in ('news', 'events', 'features')
group by company
*the list group_concat(copy order by copy) cannot be too long though, which depends on your data.