Mysql: Order By with numerical value shows wrong order - mysql

I'm using Spring Boot 2.2.6.RELEASE. I have a repository method looks like this:
#Query(value = "SELECT m FROM Media m ORDER BY m.viewCount DESC")
Page<Media> findMedias(Pageable pageable);
I get unordered result list with this. I tried to run the next query in the cli:
SELECT media.view_count FROM mydb.media ORDER BY media.view_count DESC;
The result looks like this:
--------------
| 9 |
| 8 |
| 7 |
| 6 |
| 5 |
| 4 |
| 3 |
| 3 |
| 20 |
| 19 |
| 18 |
| 17 |
| 16 |
| 15 |
| 13 |
| 12 |
| 12 |
| 11 |
| 10 |
| 1 |
| 1 |
--------------
I want the value of 20 to be the first and not 9. Why MySQL do this kind of order? It shows one digit value first instead of the highest number?
EDIT:
I use sql file to create my tables. view_count column has LONG as type, not String. The query looks like this:
CREATE TABLE IF NOT EXISTS media(m_id INTEGER PRIMARY KEY AUTO_INCREMENT, title VARCHAR(255) NOT NULL, category VARCHAR(10) NOT NULL, file_name VARCHAR(255) NOT NULL, view_count LONG NOT NULL, download_count LONG NOT NULL);

The view_count is stored as a string in your table which is not incorrect. If you can, then change it to integer. If you can not do that then, use the below to get the desired output.
SELECT m.view_count
FROM media m
ORDER BY CAST(m.view_count AS UNSIGNED) DESC;

Related

Conditionally select column values sql

I've got an SQL table, homes, like this:
+------------------------+-------------------+-------------------+---------------------+
| id | home_one | home_two | test_val |
+------------------------+-------------------+-------------------+---------------------+
| q6KPfv2bsnZTEdiK6McPn4 | 4214 | 1234 (*) | 8 |
| kTEHH6QA9wGGSnFDENeWHk | 6431 | 0251 | 5 |
| fjLrUzp16vKaDWYMHoyvKQ | 1234 (*) | 5381 | 8 |
| hn89YvsayDWEYziv4jZBnR | 8241 | 1682 | 4 |
| wK5QdX54A2z6uH7SKkHiao | 1234 (*) | 9375 | 8 |
+------------------------+-------------------+-------------------+---------------------+
I'd like to filter on a condition such as
SELECT home_one, home_two FROM HOMES
WHERE test_val = 8
although I don't really want to get both home_one and home_two, but I only want to get either home_one, or home_two, depending on which one does not equal '1234'.
So my idea output would be something like:
+---------+
| results |
+---------+
| 4214 |
| 5381 |
| 9375 |
+---------+
I realize this could be done in the server logic instead, but I figure if there's a way to do this in SQL, that'd be nice, since the less server logic necessary, the less strain there will be on the server.
If there's some sort of command like this that can conditionally choose which column value to take for each row that would be what I'm looking for!
For reference, too, something like this is what would be used to make the homes table:
CREATE TABLE homes(
id character varying(24) NOT NULL,
home_one character varying (24) NOT NULL,
home_two character varying(24) NOT NULL,
PRIMARY KEY id
);
Just add the logic you mentioned to the WHERE clause:
SELECT CASE WHEN home_one <> '1234' THEN home_one ELSE home_two END AS home
FROM HOMES
WHERE test_val = 8 AND
(home_one = '1234' AND home_two <> '1234' OR
home_one <> '1234' AND home_two = '1234');

Disable MySQL to convert string to 0 [duplicate]

I came across this auto typecasting of MYSQL from String to Integer seems to me weird.
mysql> select * from `isps` where `id` = '3ca6fb49-9749-3099-b30d-19ce56349ad6' OR `unique_id` = '3ca6fb49-9749-3099-b30d-19ce56349ad6';
+----+--------------------------------------+---------------+--------------+---------------------+---------------------+
| id | unique_id | name | code | created_at | updated_at |
+----+--------------------------------------+---------------+--------------+---------------------+---------------------+
| 3 | ee8db3be-1bf7-3440-8add-37232cfc4ecb | TTN | ttn | 2019-09-26 08:12:14 | 2019-09-26 08:12:14 |
| 7 | 3ca6fb49-9749-3099-b30d-19ce56349ad6 | ONE BROADBAND | onebroadband | 2019-09-26 08:12:14 | 2019-09-26 08:12:14 |
+----+--------------------------------------+---------------+--------------+---------------------+---------------------+
I had not expected result with id = 3 can anyone help with this.
DataType in my database
id - BIGINT
unique_id - varchar(200)
You can cast id to a string before comparing.
select * from `isps` where CAST(`id` AS CHAR) = '3ca6fb49-9749-3099-b30d-19ce56349ad6' OR `unique_id` = '3ca6fb49-9749-3099-b30d-19ce56349ad6';
Note that this will slow down the query significantly, since it won't be able to use the index on the id column.

Select value from table sorted by a certain order from another table

I want to select value from table sorted by a certain order.
I have a table called test that looks like this:
| date | code | value |
+----------+-----------+----------+
| 20050104 | 000005.SZ | -6359.19 |
| 20050104 | 600601.SH | -7876.34 |
| 20050104 | 600602.SH | -25693.3 |
| 20050104 | 600651.SH | NULL |
| 20050104 | 600652.SH | -15309.9 |
...
| 20050105 | 000005.SZ | -4276.28 |
| 20050105 | 600601.SH | -3214.56 |
...
| 20170405 | 000005.SZ | 23978.13 |
| 20170405 | 600601.SH | 32212.54 |
Right now I want to select only one date, say date = 20050104, and then sort the data by a certain order (the order that each stock was listed in the stock market).
I have another table called stock_code which stores the correct order:
+---------+-----------+
| code_id | code |
+---------+-----------+
| 1 | 000002.SZ |
| 2 | 000004.SZ |
| 3 | 600656.SH |
| 4 | 600651.SH |
| 5 | 600652.SH |
| 6 | 600653.SH |
| 7 | 600654.SH |
| 8 | 600602.SH |
| 9 | 600601.SH |
| 10 | 000005.SZ |
...
I want to sorted the selected data by stock_code(code_id), but I don't want to use join because it takes too much time. Any thoughts?
I tried to use field but it gives me an error, please tell me how to correct it or give me an even better idea.
select * from test
where date = 20050104 and code in (select code from stock_code order by code)
order by field(code, (select code from stock_code order by code));
Error Code: 1242. Subquery returns more than 1 row
You told us that you don't want to join because it takes too much time, but the following join query is probably the best option here:
SELECT t.*
FROM test t
INNER JOIN stock_code sc
ON t.code = sc.code
WHERE t.date = '20050104'
ORDER BY sc.code_id
If this really runs slowly, then you should check to make sure you have indices setup on the appropriate columns. In this case, indices on the code columns from both tables as well as an index on test.date should be very helpful.
ALTER TABLE test ADD INDEX code_idx (code)
ALTER TABLE test ADD INDEX date_idx (date)
ALTER TABLE code ADD INDEX code_idx (code)

Get distinct results from several tables

I need to implement mysql query to calculate space used by user's mailbox.
A message thread may have multiple messages (reply, follow up) by 2 parties
(sender/recipient) and is tagged with one or more tags (Inbox, Sent etc.).
The following conditions have to be met:
a) user is either recipient OR author of the message;
b) message IS TAGGED by any of the tags: 1,2,3,4;
c) distinct records only, ie if the thread, containing messages is tagged with
more than one of the 4 tags (for example 1 and 4: Inbox and Sent) the calculation
is done on one tag only
I have tried the following query but I am not able to get distinct values - the
subject/body values are duplicated:
SELECT SUM(LENGTH(subject)+LENGTH(body)) AS sum
FROM om_msg_message omm
JOIN om_msg_index omi ON omm.mid = omi.mid
JOIN om_msg_tags_index omti ON omi.thread_id = omti.thread_id AND omti.uid = user_id
WHERE (omi.recipient = user_id OR omi.author = user_id) AND omti.tag_id IN (1,2,3,4)
GROUP BY omi.mid;
Structure of the tables:
om_msg_message - fields subject and body are the ones to be calculated
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| mid | int(10) unsigned | NO | PRI | NULL | auto_increment |
| subject | varchar(255) | NO | | NULL | |
| body | longtext | NO | | NULL | |
| timestamp | int(10) unsigned | NO | | NULL | |
| reply_to_mid | int(10) unsigned | NO | | 0 | |
+--------------+------------------+------+-----+---------+----------------+
om_msg_index
+-----+-----------+-----------+--------+--------+---------+
| mid | thread_id | recipient | author | is_new | deleted |
+-----+-----------+-----------+--------+--------+---------+
| 1 | 1 | 1392 | 1211 | 0 | 0 |
| 2 | 1 | 1211 | 1392 | 1 | 0 |
+-----+-----------+-----------+--------+--------+---------+
om_msg_tags_index
+--------+------+-----------+
| tag_id | uid | thread_id |
+--------+------+-----------+
| 1 | 1211 | 1 |
| 4 | 1211 | 1 |
| 1 | 1392 | 1 |
| 4 | 1392 | 1 |
+--------+------+-----------+
Here's another solution:
SELECT SUM(LENGTH(omm.subject) + LENGTH(omm.body)) as totalLength
FROM om_msg_message omm
JOIN om_msg_index omi
ON omi.mid = omm.mid
AND (omi.recipient = user_id OR omi.author = user_id)
JOIN (SELECT DISTINCT thread_id
FROM om_msg_tags_index
WHERE uid = user_id
AND tag_id IN (1, 2, 3, 4)) omti
ON omti.thread_id = omi.thread_id
I'm assuming that:
user_id is a parameter marker/host variable, being queried for an individual user.
You want the total of all messages per user, not the total length of each message (which is what the GROUP BY clause in your version was getting you).
That mid in both om_msg_message and om_msg_index is unique.
So, your problem is the IN clause. I'm not a MYSQL guru, but in T-SQL you could change it to have a where clause on a subquery that contained an EXISTS so your join didn't pop out two rows. You need to compensate for the fact that you have two rows with different tagID's associated with each row of your primary join data.
The way I could do it cross-platform would be with four left-joins that linked tables then demanded a non-null value for 1, 2, 3, or 4. Fairly inefficient; I'm sure there's a better way to do it in MySQL, but now that you know what the problem is you might know a better solution.

Getting most recent entries when using GROUP BY in RoR

I have a table organized in the following way:
id | userid | action | notes | created_at
-----------------------------------------
1 | 1 | foo | bar | datetime
2 | 33 | foo | bax | datetime
3 | 1 | foo | okay | datetime
4 | 3 | bam | bad | datetime
5 | 33 | foo | bom | datetime
What I would like to be able to do is, in Ruby on Rails, group the rows by userid but grab only the most recent entry for each group.
As it stands, I've gotten this far:
Thing.select("userid, notes").where(:action => "foo").order('`when` DESC')
Which will usually return something like:
userid | notes
--------------
1 | bar
33 | bax
When what I'm looking for is this:
userid | notes
--------------
1 | okay
33 | bom
I think I copy/pasted that all right...heh. Is there a way to achieve what I'm trying to do? Without resorting to searching inside my app itself? Thanks.
Update Attempted the first suggestion, no dice.
Just add .order("id desc") to the end of your line