Retrieving two highest values from one column for ranked comparison of difference - mysql

MODIFIED TO ADD INFORMATION:
I realize that there have been many "get two highest" or "get second-highest" SQL questions and answered posted, so I apologize in advance if this question is redundant, but I want to do something a bit different than the other situations, and I need some help getting from A to B. I am a MySQL hobbyist at best, so I'm sure the answer is obvious to some of you.
I have a bunch of rows of baseball player single-season statistics. I want to compare their season with the highest value with their season with the second highest value. I also want to be able to compare the two seasons by subtracting the second-highest from the highest.
I can easily get the highest value using MAX, of course, but this is a big more difficult for a novice like myself.
Thanks for your help so far.
I will simplify the relevant table structure so that it is relevant:
playerid, Year, Value
Each Player-season is separated by year.
What i want returned from my query is
Player id,
Year [of Highest Value],
Value [Highest],
Year [of Second Highest Value],
Value [Second-Highest]
I hope that is simple enough and clear. Thanks for any help.

Without knowing your table structure, you could essentially do:
SELECT score
FROM statstable
WHERE playerID=???
ORDER BY score DESC
LIMIT 2
which would retrieve the two rows with the highest scores, which you can the pull out the scores and subtract in your client.
If you need this highest-next_highest value for user in another query, then it gets a bit more complicated.

Related

Very basic question about dividing two MySQL table columns

So, I'm just beginning learning SQL today. I have a table in MySQL and need to find the gdp per capita and make a new column out of it (or potentially just assign it to a column I have already made if making a new one isn't possible), I have a column with the countries' gdp and the countries' population, both of which have been given the type BIGINT. But how might I divide those two numbers together and have them in descending order and I want to print them out?
The code I have so far is:
SELECT countries_name, countries_population, countries_gdp
FROM countries.countries
WHERE (countries_population / countries_gdp) countries_per_capita_gdp
ORDER BY DESC
Would anyone be able to give me a hint as to what I might be doing wrong please? Our lecturer is giving us very little guidance on this so I think most of us are confused, unfortunately.
I think what you're looking for is this:
SELECT countries_name, countries_population, countries_gdp, (countries_population / countries_gdp) AS countries_per_capita_gdp
FROM countries
ORDER BY countries_per_capita_gdp DESC
I noticed your FROM had countries.countries, not sure if that was intentional, might just have to be countries.

SQL query and for loops

I need a bit of help with a MySQL query. Right now I have a table that has 3 columns: location, street, and number. I want to write a query whose pseudocode would be...
for each location:
for each of the streets of a location
find the next biggest number
I feel like I am still thinking in "for-loop" logic, but that doesn't really seem to be the way MySQL operates, and it is tripping me up. Any help is greatly appreciated!
Also the primary key is the location-street combo
If I understand you right, you want the highest number of each street in each location?
SELECT
location,
street,
MAX(number)
FROM table
GROUP BY
location,
street
First of all, GROUP BY aggregates ("collapses") rows, so that only one row per location and street will be returned. In the list of rows to return, we then explicitly specify we want the highest number (MAX()) instead of the first one that would show up.
http://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
http://dev.mysql.com/doc/refman/5.6/en/example-maximum-column.html
http://dev.mysql.com/doc/refman/5.6/en/select.html
If it helps, you can think of a SELECT query (albeit very crudely) as filter rules for a loop that goes through every row of the entire table. In these "filter rules" you specify precisely what you want and how you want it, MySQL will then iterate over the entire table and handpick exactly the data you asked for.

How should I setup the structure of my MySQL database to work for my needs?

I am working on an application that awards the top person of each category for being first. The way you become first in a category is by having the most number of votes in the past 30 (or so) days. So even if you had a total of 2,000 votes but got only 2 votes within the past 30 days, someone with 10 votes but got all 10 within the past 30 days would be ranked above you. I am just trying to seek advise on the best way to create this type of system with a MySQL database and how to structure the database.
I am pretty unsure of the best way to go about this, any advice would be greatly appreciated!
The first desicion you have to make is, whether you want to keep a record for every vote cast: This has the potential for a huge table, but it lets you keep a lot of information, so you trade storage and performance against information. This must be answered by business logic, not implementation.
Assuming you DO want to keep every vote, keep it with a timestamp and the only thing you have to do is to join the user person table with the vote table, use a WHERE clause to select only the last N days and a COUNT() aggregate to count your votes.
If you do NOT want to keep every vote, you should have an accumulation table with person, day and votecount - an analogous query with SUM() instead of COUNT() will do what you want.

Retention Tracking

Let’s say I have an Angry Birds game.
I want to know how many players are buying the ‘mighty eagle’ weapon each month out of the players which bought the mighty eagle weapon in the previous months in their LTV in the system
I have the dates of all items bought per each client.
What I practically would like to have is a two dimensional
matrix that will tell me what the percentage of the players which moved from
LTV_month_X to LTV_month_Y for each combination of X<Y for a specific current
month?
An example:
example_png
(it didn't let me to put the pic inline so please press the link to see the pic)
Now, I have found a way to get the number of players moved
actually from from LTV_month_X to LTV_month_Y that LTV_month_Y is their current
month of activity within the system using SQL query and Excel Pivot table.
What I try find out is mainly is how to get the base number of those who potentially could do that transition.
A few definitions:
LTV_month_X = DATEDIFF(MONTH, first_eagle_month, specific_eagle_month)+1
Preferably I would like to have the solutions in ANSI-SQL, if not then MySQL or
MSSQL but no Oracle functions should be used at all.
Since I’m looking for the percentage of the transition two-steps plans could also work, first find the potential ones and the find the actual ones who moved to measure the retention from  LTV_month_X to LTV_month_Y.
One last issue: I need for it to be possible to drill down and find the actual IDs of the clients who moved from any stage X to any other stage Y (>X).
The use of the term LTV here is not clear. I assume you mean the lifetime of the user.
If I understand the question, you are asking, based on a list of entities each with one or more events, how do I group (e.g. count) the entities by the month of the last event and the month of the one before last event.
in mysql, you can use a variable to do that. I'm not going to expalin the whole concept, but basically, when within a SELECT statement you write #var:=column, then that variable is assigned the value of that column, and you can use that to compare values between consectuive columns e.g.
LEAST(IF(#var=column,#same:=#same+1,#same:=0),#var:=column)
the use of LEAST is a trick to ensure execution order.
The two dimension you are looking for are
Actual purchase month
Relative purchase month
SELECT
player_id,
TRUNCATE(first_purchase,'MM') AS first_month ,
TRUNCATE(current_purchase_date ,'MM') AS purchase_month,
months_between(current_purchase _date, first_purchase_date)+1 AS relative_month,
SUM(purchase_amount) AS total_purchase,
COUNT(DISTINCT player_id) AS player_count
FROM ...
Now you can pivot purchase month to relative month and aggregate

MySQL Query eliminate duplicates but only adjacent to each other

I have the following query..
SELECT Flights.flightno,
Flights.timestamp,
Flights.route
FROM Flights
WHERE Flights.adshex = '400662'
ORDER BY Flights.timestamp DESC
Which returns the following screenshot.
However I cannot use a simple group by as for example BCS6515 will appear a lot later in the list and I only want to "condense" the rows that are the same next to each other in this list.
An example of the output (note BCS6515 twice in this list as they were not adjacent in the first query)
Which is why a GROUP BY flightno will not work.
I don't think there's a good way to do so in SQL without a column to help you. At best, I'm thinking it would require a subquery that would be ugly and inefficient. You have two options that would probably end up with better performance.
One would be to code the logic yourself to prune the results. (Added:) This can be done with a procedure clause of a select statement, if you want to handle it on the database server side.
Another would be to either use other information in the table or add new information to the table for this purpose. Do you currently have something in your table that is a different value for each instance of a number of BCS6515 rows?
If not, and if I'm making correct assumptions about the data in your table, there will be only one flight with the same number per day, though the flight number is reused to denote a flight with the same start/end and times on other days. (e.g. the 10a.m. from NRT to DTW is the same flight number every day). If the timestamps were always the same day, then you could use DAY(timestamp) in the GROUP BY. However, that doesn't allow for overnight flights. Thus, you'll probably need something such as a departure date to group by to identify all the rows as belonging to the same physical flight.
GROUP BY does not work because 'timestamp' value is different for 2 BCS6515 records.
it will work only if:
SELECT Flights.flightno,
Flights.route
FROM Flights
WHERE Flights.adshex = '400662'
GROUP BY (Flights.flightno)