MySQL data sort - mysql

I have a table that has four columns: id, item_number, feature, value.
The table looks like this and has about 5 million entries.
╔════╦═════════════╦═════════╦═══════╗
║ id ║ item_number ║ feature ║ value ║
╠════╬═════════════╬═════════╬═══════╣
║ 1 ║ 234 ║ 5 ║ 15 ║
║ 2 ║ 234 ║ 3 ║ 256 ║
║ 3 ║ 453 ║ 5 ║ 14 ║
║ 4 ║ 453 ║ 4 ║ 12 ║
║ 5 ║ 453 ║ 7 ║ 332 ║
║ 6 ║ 17 ║ 5 ║ 88 ║
║ 7 ║ 17 ║ 9 ║ 13.86 ║
╚════╩═════════════╩═════════╩═══════╝
How can I sort the table so that I can get the item_numbers in descending order based on the feature value?
I am also selecting other feature numbers with their values but I only want to sort by feature number 5.

You need to do order by first with feature and then with item_numbers
select * from `table` order by `feature`, `item_numbers` desc

Using order by with desc and where clauses:
select `item_numbers`
from `tbl`
where `feature` = 5
order by `value` desc

In your query, add
order by item_number desc
If you are trying to query based on a specific feature, so only receive one set of data for a feature at at time, add
where feature = 'feature'
where "feature" is the feature value you want to search for. If you are looking to provide all features but sort them, you can add
order by feature, item_number desc
and you will be give all features in ascending order and together (grouped) then the items_number(s) in descending order
EDIT::
Sounds like from your latest comment, this may be your solution:
SELECT item_number FROM table WHERE feature = '5' ORDER BY value DESC

Related

Subquery returns more than 1 row when aggregation is used

Subquery returns more than 1 row??
SELECT
`employee`.`employee_id` AS `employee_id`,
(
SELECT
SUM(company.company_profit_left)
FROM
company
GROUP BY
company.employee_id,
company.employee_department
) AS profit_left
FROM
employee
LEFT JOIN `company` ON `company`.`employee_id` = `employee`.`employee_id`
GROUP BY
`employee`.`employee_id`
HAVING
SUM(
company.company_profit_left
) = 0
╔════╦══════════════╦════════════╦════════════╦
║ id ║ user_id ║ profit left║ department ║
╠════╬══════════════╬════════════╬════════════╬
║ 1 ║ 1 ║ 100 ║ 1 ║
║ 2 ║ 2 ║ 50 ║ 1 ║
║ 3 ║ 1 ║ 30 ║ 2 ║
║ 4 ║ 2 ║ 20 ║ 1 ║
║ 5 ║ 2 ║ 20 ║ 3 ║
╚════╩══════════════╩════════════╩════════════╩
and the below table is what I want to achieve
╦══════════════╦══════════════╦
║ user_id ║ profit left ║
╠══════════════╬══════════════╬
║ 1 ║ 100 ║
║ 1 ║ 30 ║
║ 2 ║ 70 ║
║ 2 ║ 20 ║
╚══════════════╩══════════════╩
that's why I thought I needed to use group by to distinguish user_id
I have already looked at
Subquery returns more than 1 row - MySQL
subquery returns more than 1 row?
but still don't understand.
By joining two different tables, I get the below table.
anyone can help me solve the problem ?
Edit: Based on table structure and output required, I updated the query and removed unwanted where and left join.
I don't know what you're trying to do. But based on my understanding I corrected your query:
SELECT
employee.employee_id AS employee_id,
profit_left.employee_department
profit_left.company_profit
FROM
employee
JOIN (
SELECT
company.employee_id,
company.employee_department,
SUM(company.company_profit_left) as company_profit
FROM company
GROUP BY company.employee_id,company.employee_department
) AS profit_left on employee.employee_id=profit_left.employee_id
I think you want a correlated subquery. I'm not sure what you are really doing, but this should fix your error:
(SELECT SUM(company.company_profit_left)
FROM company c
WHERE c.employee_id = e.employee_id
) AS profit_left
You might want this by department instead. But the point is that aggregation is not appropriate for the subquery. A correlation clause is appropriate.
Your sub query grouping all the employee in company tabel and not one of them.you must put where condition in sub query to filter records and no need to grouping in sub query.

Mysql Update column with subrequest Order By

I have a table biblek2 items with those 4 columns :
id (autoincrement)
catid(int)
introtext(varchar)
ordering(int)
Table biblek2_items
╔════╦═══════╦═══════════╦══════════╗
║ ID ║ catid ║ introtext ║ ordering ║
╠════╬═══════╬═══════════╬══════════╣
║ 1 ║ 3024 ║ orange ║ 122 ║
║ 2 ║ 2024 ║ zebra ║ 45 ║
║ 3 ║ 3010 ║ juice ║ 55 ║
║ 4 ║ 3002 ║ build ║ 17 ║
║ 5 ║ 2003 ║ car ║ 87 ║
║ 6 ║ 1610 ║ other ║ 1521 ║
║ 7 ║ 1620 ║ other ║ 200 ║
╚════╩═══════╩═══════════╩══════════╝
I expect that
Table biblek2_items
╔════╦═══════╦═══════════╦══════════╗
║ ID ║ catid ║ introtext ║ ordering ║
╠════╬═══════╬═══════════╬══════════╣
║ 5 ║ 2003 ║ car ║ 1 ║
║ 4 ║ 3002 ║ build ║ 2 ║
║ 3 ║ 3010 ║ juice ║ 3 ║
║ 1 ║ 3024 ║ orange ║ 4 ║
║ 2 ║ 2024 ║ zebra ║ 5 ║
╚════╩═══════╩═══════════╩══════════╝
I want to
select * from biblek2_items where catid between 2001 and 3024
ORDER BY introtext ASC
empty the ordering column
reorder the ordering column by increment from 1 to n according to the result of the order column
I tried this with no success
DECLARE #variable int
SET #variable = 0
UPDATE `biblek2_items`
SET #variable = ordering = #variable + 1
WHERE ordering IN (SELECT ordering
FROM `biblek2_items`
WHERE catid BETWEEN 2001 AND 3024
ORDER BY `introtext` DESC)
I read in the forum that MySQL can't allow subrequests with ORDER BY, so could you help me
As explained in the comments :
The ORDER BY in your sub query makes no sense anyway, because, you don't LIMIT. So all rows will be returned and it doesn't matter how they are ordered because all of them are taken into account with the IN in your main query.
But there are other issues with your query.
Do this instead :
SET #row_number = 0 ;
UPDATE biblek2_items,
(select id, catid,introtext,ordering, (#row_number:=#row_number + 1) AS newordering
from biblek2_items
where catid between 2001 and 3024
ORDER BY introtext ASC
) as temp
SET biblek2_items.ordering = temp.newordering
WHERE biblek2_items.ID = temp.ID
Additionally, if you have a large table, and a lot of users actively writing on it, to avoid inconsistencies or locking issues, I would suggest a slightly different method, using a temporary table to store the computed new ordering.
CREATE TABLE biblek2_items_TEMP (ID INT, ordering INT);
SET #row_number = 0 ;
INSERT INTO biblek2_items_TEMP
select id, (#row_number:=#row_number + 1) AS newordering
from biblek2_items
where catid between 2001 and 3024
ORDER BY introtext ASC
;
UPDATE biblek2_items, biblek2_items_TEMP
SET biblek2_items.ordering = biblek2_items_TEMP.ordering
WHERE biblek2_items.ID = biblek2_items_TEMP.ID;
DROP TABLE biblek2_items_TEMP;
Tested successfully on MySQL 5.7 and MariaDB 10

SQL My Sub Query is Loading Forever

Okay so basically I am trying to run a simple query with a subquery on phpmyadmin using mysql and it won't stop loading after I run it. The query is:
SELECT t.tagValue FROM tags t WHERE t.tagID IN (SELECT ua.tagID FROM user_taggedArtists ua WHERE ua.userID = 2);
I have ran the individual queries on their own without combining them together and they seem to do what I want, but when I mix them into a subquery form phpmyadmin just loads forever, like I am getting an infinite loop or something.
tags table looks like that:
╔═══════╦═════════════╗
║ tagID ║ tagValue ║
╠═══════╬═════════════╣
║ 1 ║ metal ║
║ 2 ║ alternative ║
║ 3 ║ pop ║
╚═══════╩═════════════╝
etc.
user_taggedArtists table looks like this:
╔════════╦══════════╦═══════╦═════╦═══════╦═══════╗
║ userID ║ artistID ║ tagID ║ day ║ month ║ year ║
╠════════╬══════════╬═══════╬═════╬═══════╬═══════╣
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
╚════════╩══════════╩═══════╩═════╩═══════╩═══════╝
ect.
Not sure what I am doing wrong here and any help would be greatly appreciated.
Thank you!
Hard to say 'zatly, but "IN", generally, is slow. Try a JOIN and WHERE. I'm going to pretend we can join on tagID. You should have indexes on the join column(s). If not anything you do will perform poorly.
SELECT t.tagValue
FROM tags t
INNER JOIN user_taggedArtists ua ON
t.tagID = ua.tagID
WHERE ua.userID = 2

MySQL - Merge rows in table based on multiple criteria

I'd like to merge rows based on multiple criteria, essentially removing duplicates where I get to define what "duplicate" means. Here is an example table:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 2 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
║ 5 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
In my example, let's say I want to merge on name and age but ignore grade. The result should be:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
I don't particularly care if the id column is updated to be incremental, but I suppose that would be nice.
Can I do this in MySQL?
My suggestion, based on my above comment.
SELECT distinct name, age, grade
into tempTable
from theTable
This will ignore the IDs and give you only a distinct dump, and into a new table.
Then you can either drop the old and, and rename the new one. Or truncate the old one, and dump this back in.
You could just delete the duplicates in place like this:
delete test
from test
inner join (
select name, age, grade, min(id) as minid, count(*)
from test
group by name, age, grade
having count(*) > 1
) main on test.id = main.minid;
Example: http://sqlfiddle.com/#!9/f1a38/1

SQL Query Get Max Value At Occured Date

So we are doing some traffic reporting in our department.
Therefore we got a table named traffic_report, which is build up like
╔════════════════╦═══════════╦═════════════════════╦═════════════╦═════════════╗
║ hostname ║ interface ║ date_gmt ║ intraf_mpbs ║ outraf_mbps ║
╠════════════════╬═══════════╬═════════════════════╬═════════════╬═════════════╣
║ my-machine.com ║ NIC-5 ║ 2013-09-18 09:55:00 ║ 32 ║ 22 ║
║ my-machine.com ║ NIC-5 ║ 2013-09-17 08:25:00 ║ 55 ║ 72 ║
║ my-machine.com ║ NIC-5 ║ 2013-09-16 05:12:00 ║ 65 ║ 2 ║
║ my-machine.com ║ NIC-5 ║ 2013-09-15 04:46:00 ║ 43 ║ 5 ║
║ my-machine.com ║ NIC-5 ║ 2013-09-14 12:02:00 ║ 22 ║ 21 ║
║ my-machine.com ║ NIC-5 ║ 2013-09-13 22:13:00 ║ 66 ║ 64 ║
╚════════════════╩═══════════╩═════════════════════╩═════════════╩═════════════╝
I'd like to fetch the maximum of the traffic in and traffic out at the occured date.
My approach doing so is like this
SELECT hostname, interface, date_gmt, max(intraf_mbps) as max_in, max(outtraf_mbps) as max_out
FROM traffic_report
GROUP by hostname, interface
The approach produces a table like this
╔════════════════╦════════════╦═════════════════════╦════════╦═════════╗
║ hostname ║ interface ║ date_gmt ║ max_in ║ max_out ║
╠════════════════╬════════════╬═════════════════════╬════════╬═════════╣
║ my-machine.com ║ NIC-5 ║ 2013-09-18 09:55:00 ║ 66 ║ 72 ║
╚════════════════╩════════════╩═════════════════════╩════════╩═════════╝
The problem is, the date_gmt displayed is just the date of the first record entered to the table.
How do I instruct SQL to display me the date_gmt at which the max(intraf_mbps) occured?
Your issue is with mysql hidden fields:
MySQL extends the use of GROUP BY so that the select list can refer to
nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group.
Mysql has not rank features either analytic functions, to get your results, a readable approach but with very poor performance is:
SELECT hostname,
interface,
date_gmt,
intraf_mbps,
outtraf_mbps
FROM traffic_report T
where intraf_mbps + outtraf_mbps =
( select
max(intraf_mbps + outtraf_mbps)
FROM traffic_report T2
WHERE T2.hostname = T.hostname and
T2.interface = T.interface
GROUP by hostname, interface
)
Sure you can work for a solution with more index friendly approach or avoid correlated subquery.
Notice than I have added both rates, in and out. Adapt solution to your needs.
Either of these approaches should work:
This first query returns the rows that match the maximum out and in values, so multiple rows can be returned if many records share the max or min values.
SELECT * from traffic_report
WHERE intraf_mpbs = (SELECT MAX(intraf_mpbs) FROM traffic_report)
or outraf_mpbs = (SELECT MAX(outraf_mpbs) FROM traffic_report)
This second query returns more of a MI style result, add other fields if you require them.
SELECT "MAX IN TRAFFIC" AS stat_label,date_gmt AS stat_date, traffic_report.intraf_mpbs
FROM traffic_report,(select MAX(intraf_mpbs) AS max_traf FROM traffic_report) as max_in
WHERE traffic_report.intraf_mpbs = max_in.max_traf
UNION
SELECT "MAX OUT TRAFFIC" AS stat_label,date_gmt AS stat_date, traffic_report.outraf_mpbs
FROM traffic_report,(SELECT MAX(outraf_mpbs) AS max_traf FROM traffic_report) AS max_out
WHERE traffic_report.outraf_mpbs = max_out.max_traf
Hope this helps.