mysql show rows in order from highest value to lowest value - sql

I have a table that contains a column named views. Each time the user refreshes the page, it updates the view count +1.
What im trying to do, is create a mysql query to output the list of rows based on their views count, from highest to lowest.
this is what i thought would work
SELECT * FROM picdb ORDER BY views DESC LIMIT 10
even when i view it ASCENDING, its all out of whack.
thoughts?
EDIT
the column type is TEXT
SOLVED changed column type to INT and it works fine now. Thanks for pointing it out.

If your column type is TEXT, the default sorting behavior treats the data as strings, and therefore sorts them alphabetically (not numerically).
Change your column type to a number type, and it will sort correctly.

SELECT
*
FROM
tbl
ORDER BY
CAST(views AS UNSIGNED) DESC
LIMIT
10
Might do the trick. The real question is why you have a column containing integers with the text type?

select a,b,CAST(views AS UNSIGNED) c from picdb order by c desc limit 10

This looks like the classic alphanumeric sort problem. If the column type is text, then you are probably seeing order like 1, 10, 15, 20, 3. In other words, it’s sorting by the text value instead of the integer value.
You could change the column to a numeric type, or you could do:
SELECT * FROM picdb ORDER BY CONVERT(views, UNSIGNED INTEGER) DESC LIMIT 10
However, this would not be able to take advantage of any index on the views column. It would be better to change the column to a numeric type if that is indeed what it represents.

If you want to show your table rows from higher value to lower value then use this query.
query = "SELECT * FROM CurrencyTable ORDER BY CAST(currency_rate AS UNSIGNED) DESC";
And if you want to show rows from lower value to higher value then use this query
query-2 = "SELECT * FROM CurrencyTable ORDER BY CAST(currency_rate AS UNSIGNED) ASC";

Related

Acquiring offset of some row in SQL

TL;DR: Is there a possibility to get OFFSET position of a particular, known row in SQL, considering some ORDER BY is applied?
So consider a schema like this (simplified):
CREATE TABLE "public"."painting" (
"uuid" uuid NOT NULL DEFAULT uuid_generate_v4(),
"name" varchar NOT NULL,
"score" int4 NOT NULL,
"approvedAt" timestamp,
PRIMARY KEY ("uuid")
);
Like
abc1,test1,10,10:00
abc2,test2,9,11:00
abc3,test3,8,8:00
abc4,test4,8,12:00
abc5,test5,6,7:00
I want to make a request sorted by score and limited with 3 items, and I should emphasize that multiple entities might have the same score.
Because of a dynamic nature of that table, while traversing through those items, sorted by score, some new item might appear somewhere in the list.
If I use SQL OFFSET statement, that means this new entity will shift all entities below to one row, so that the new selection will have an item, that was last on previous 3 items selection.
abc1,test1,10,10:00
abc2,test2,9,11:00
abc6,test6,8,15:00 (new item)
CURRENT OFFSET = 3
abc3,test3,8,8:00 (was in previous select)
abc4,test4,8,12:00
abc5,test5,6,7:00
To avoid that, instead of using OFFSET, I can remember the UUID of the item I fetched last, so it'll be abc3. On next request, I can use it's score to add an extra WHERE SCORE < 8 statement, but this will skip abc4, because it's too having score of 8.
If I use WHERE SCORE <= 8 this will again return abc3 which is already traversed. I can't use another field in WHERE clause, because this will affect the results. Additional ORDER BY won't help either.
It seems to me that it is a very common problem in database selection, yet I can't find one comprehensive answer.
So, my question then, if it's possible to do some kind of request like following:
SELECT * FROM "painting" WHERE "score" <= :score ORDER BY "score" DESC OFFSET %position of `abc3`% LIMIT 3
Or alternatively
SELECT OFFSET OF (`abc3`) FROM "painting" WHERE SCORE <= :score ORDER BY "score" DESC LIMIT 3
That will return 2 (because it's the second row with such score), then do
SELECT * FROM "painting" WHERE "score" <= :score ORDER BY "score" DESC OFFSET :offset LIMIT 3
where :score is the score of last received item and :offset is the result of SELECT OFFSET - 1
My own assumption is that we have to SELECT WHERE "score" = :score, and get offset position outside the SQL (or make a very complex SQL query). Though, if we have a lot of items with similar ORDER BY attribute, this helper request might end up being heavier than the data fetch itself.
Yet, I feel like that there's a much more clever SQL way of doing what I'm trying to do.
Good question. Accurate Backend Pagination requires the underlying data to use an ordering criteria with a set of columns that represent a UNIQUE key.
In your case your ordering criteria can be made unique by adding the column uuid to it. With that in mind you can increase the page size by 1 behind the scenes to 4. That 4th row won't be displayed but only used to retrieve the next page.
For example, you can get:
select *
from painting
order by -score, approvedAt, uuid
limit 4
Now you would display the first three rows:
abc1,test1,10,10:00
abc2,test2,9,11:00
abc3,test3,8,8:00
The client app (most likely the UI) will remember -- not display -- the 4th row (the "key") to retrieve the next page:
abc4,test4,8,12:00
Then, to get the next page the query will add a WHERE clause with the "key" and take the form:
select *
from painting
where (-score, approvedAt, uuid) >= (-8, '12:00', 'abc4')
order by -score, approvedAt, uuid
limit 4
This query won't display the new row being inserted, but the original 4th row.
To get blazing fast data retrieval you could create the index:
create index ix1 on painting ((-score), approvedAt, uuid);
See example at DB Fiddle.

function to sum all first value of Results SQL

I have a table with "Number", "Name" and "Result" Column. Result is a 2D text Array and I need to create a Column with the name "Average" that sum all first values of Result Array and divide by 2, can somebody help me Pls, I must use the create function for this. Its look like this:
Table1
Number
Name
Result
Average
01
Kevin
{{2.0,10},{3.0,50}}
2.5
02
Max
{{1.0,10},{4.0,30},{5.0,20}}
5.0
Average = ((2.0+3.0)/2) = 2.5
= ((1.0+4.0+5.0)/2) = 5.0
First of all: You should always avoid storing arrays in the table (or generate them in a subquery if not extremely necessary). Normalize it, it makes life much easier in nearly every single use case.
Second: You should avoid more-dimensional arrays. The are very hard to handle. See Unnest array by one level
However, in your special case you could do something like this:
demo:db<>fiddle
SELECT
number,
name,
SUM(value) FILTER (WHERE idx % 2 = 1) / 2 -- 2
FROM mytable,
unnest(avg_result) WITH ORDINALITY as elements(value, idx) -- 1
GROUP BY number, name
unnest() expands the array elements into one element per record. But this is not an one-level expand: It expand ALL elements in depth. To keep track of your elements, you could add an index using WITH ORDINALITY.
Because you have nested two-elemented arrays, the unnested data can be used as follows: You want to sum all first of two elements, which is every second (the odd ones) element. Using the FILTER clause in the aggregation helps you to aggregate only exact these elements.
However: If that's was a result of a subquery, you should think about doing the operation BEFORE array aggregation (if this is really necessary). This makes things easier.
Assumptions:
number column is Primary key.
result column is text or varchar type
Here are the steps for your requirements:
Add the column in your table using following query (you can skip this step if column is already added)
alter table table1 add column average decimal;
Update the calculated value by using below query:
update table1 t1
set average = t2.value_
from
(
select
number,
sum(t::decimal)/2 as value_
from table1
cross join lateral unnest((result::text[][])[1:999][1]) as t
group by 1
) t2
where t1.number=t2.number
Explanation: Here unnest((result::text[][])[1:999][1]) will return the first value of each child array (considering you can have up to 999 child arrays in your 2D array. You can increase or decrease it as per your requirement)
DEMO
Now you can create your function as per your requirement with above query.

Access VBA: Get difference in value between current and previous record

I have made report based on query according to this link:
http://www.techonthenet.com/access/queries/max_query2.php
It gives me list of records with values:
(primaryKey)
ID.......FirstNum....SecNum.....Diameter.....Owner
1........100200.......01...............150..............Peter
2........100200.......02...............138..............Peter
3........100300.......07...............112..............John
Query sorts records in descending order by Diametral. I want make new column which will count difference between first and second record, then between third and second and so on. Like this:
(primaryKey)
ID.......FirstNum....SecNum.....Diameter.....DiffDiametral.....Owner
1........100200.......01...............150.......................................Peter
2........100200.......02...............138.............12......................Peter
3........100300.......07...............112.............26.....................John
What should I write into RowSource or DataSource for DiffDiametral to get these values? How can I avoid error for first line, where is not previous value which I want substract from?
I tried to solve it according to this link:
http://support.microsoft.com/kb/101081/en-us
but I did not solve it. Simply I dont know how I can refer previous value of Diameter to count difference.
Based on your information, a subquery should do it. Just substitute your actual table name for tblDiameters.
SELECT C.ID, C.FirstNum, C.SecNum, C.Diameter, C.Owner,
(SELECT TOP 1 P.Diameter
FROM tblDiameters AS P
WHERE P.Diameter < C.Diameter
ORDER BY P.Diameter DESC )
- C.Diameter AS DiffDiameter
FROM tblDiameters AS C

What does ORDER BY 5 DESC mean?

SELECT Departamentos.Nome_Dep,
Funcionarios.Nome AS Funcionario,
Funcionarios.Salario,
AVG(Funcionarios.Salario) OVER(PARTITION BY Departamentos.Nome_Dep) "Média por Departamento"
Salario - AVG(Funcionarios.Salario) OVER(PARTITION BY Departamentos.Nome_Dep) "Diferença de Salário" FROM Funcionarios
INNER JOIN Departamentos
ON Funcionarios.ID_Dep = Departamentos.ID
ORDER BY 5 DESC
The Order By 5 is throwing me off. I've never anything like it. Order By [colunmname] yes, but Order By [number], never seen before. I pulled this off an article.
Note: This is T-SQL.
Source: Window Functions in SQL Server 2005, 2008, 2012
This will order by the 5th field in this SELECT statement
Order by the 5th column in the result set.
The number represents the index of the column within your select list.
Source: http://mattberseth.com/blog/2007/05/quick_tip_order_by_1_descendin.html
Order by fifth column in the result set descending.
It is the SORTING BY RELATIVE POSITION.
You can use the SQL ORDER BY clause to sort by relative position in the result set, where the first field in the result set is 1. The next field is 2, and so on.
Here in this case Order by 5th field in the result set.
Go through http://www.techonthenet.com/sql/order_by.php
about sql order by.
Useful when a similar column name has become a calcuated output field,
In the following example, it would be confusing if say 'order by numberofVioation' as this column name has just become the name of a query output SUM field (of the same old column data)
So it become useful in calculated output field
Example:
Original fields:
name| Type| RiskLevel| Date| results| violations|
/* now add an extra Sum of Violation for each type, pls note 'order by 2 desc' refers to order by the 2nd queried column, ie hi to low */
select Type, sum(numberOfViolations) as numberOfViolations
from restaurantsTable
group by Type
order by 2 desc
Order by 5th field in the result set.

SQL (Mysql) order problem

I have the following query:
SELECT a.field_eventid_key_value, a.field_showdate_value, b.nid , c.nid AS CNID
FROM content_type_vorfuehrung AS a
LEFT JOIN content_type_movies as b ON a.field_eventid_key_value = b.field_eventid_value
LEFT JOIN content_type_sonderveranstaltung as c ON a.field_eventid_key_value = c.field_sonderveranstaltungid_value
WHERE /* something */
GROUP BY a.field_eventid_key_value, a.field_showdate_value,
ORDER BY a.field_showdate_value ASC,a.field_showtime_value ASC
(where clause removed since it's irrelevant to the question)
This pulls data from 3 different tables and sorts it according to the "showdate" field in the first table. This is used in a PHP function that returns an array with the results.
Now there is a new requirement: The table "content_type_movies" in this query has a field that's supposed to be a boolean (actually it's an int with a value of either "0" oder "1"). This field is supposed to override the chronological ordering - that is, results where the field is "true" (or "1" respectively) should appear at the beginning of the result array (with the remaining entries ordered chronologically as before).
Is this at all possible with a single query ?
Thank you in advance for your time,
eike
You can use:
ORDER BY b.MyIntField DESC,
a.field_showdate_value,
a.field_showtime_value
where MyIntField is the field that is either 1 or 0 that you want to sort first.
ORDER BY a.content_type_movies DESC, /*then other fields*/ a.field_showdate_value ASC,a.field_showtime_value ASC
that should place all rows with content_type_movies=1 first then others.