Multiple Order by (date and time ) not working in MYSQL - mysql

I am combining multiple tables, filtering and then ordering by certain format. Every time I try to order by both date and time, it messes up the output.
SELECT
t1.empid,t2.lastName,t2.firstName
,t1.date as "OVERBOOKED DATE",t1.sfrom,t1.dept as "dname"
,t3.manager as "MANAGER"
from schedule_2 as t1
INNER JOIN employees_2 as t2 ON t1.empid = t2.empid
INNER JOIN dept_heads as t3 ON t1.dept = t3.Dept_name
JOIN ( SELECT empid,date from schedule_2
GROUP BY empid,date
having count(empid)>1
) inr on inr.empid=t1.empid and inr.date=t1.date
ORDER BY empid ASC, "OVERBOOKED DATE" ASC, sfrom ASC;
Im attaching the snippet of the output and the snippet of expected output. Im new to this, so would appreciate any help!
[
[

Your problem is that the values in your sfrom column are not valid inputs to the DATE function (as you are using it in your "Current Output" query). You need to use STR_TO_DATE to convert them to a valid value for ordering i.e. replace sfrom (or DATE(sfrom)) in your ORDER BY clause with
ORDER BY empid ASC, "OVERBOOKED DATE" ASC, STR_TO_DATE(sfrom, '%h%p') ASC
Edit
As has been pointed out by #TimBiegeleisen, "OVERBOOKED DATE" is just a string literal and is not valid to sort by, either the raw column name (t1.date), a regular name alias (OVERBOOKED_DATE) or the alias name in backticks should be used e.g.
ORDER BY empid ASC, `OVERBOOKED DATE` ASC, STR_TO_DATE(sfrom, '%h%p') ASC

You are storing date and time separately, which isn't usually a good idea, because it often leads to problems exactly like the one you are facing now. Given that the hour portion of your time string is fixed width, and that AM/PM sort correctly in ascending order, we can try the following:
ORDER BY
empid,
OVERBOOKED_DATE, -- DON'T use aliases with spaces, if you plan to order by them
RIGHT(sfrom, 2),
LEFT(sfrom, 2);
Note: Doing ORDER BY "OVERBOOKED DATE" appears to be ordering by a string literal, which is really no ordering at all. Instead, use the following alias:
OVERBOOKED_DATE
And then order by this single term alias.

Related

Obtaining the maximum value with Order By and Limit 1

First of all, I am using MySQL. When I make the following query:
SELECT CodE,sum(tiempo) AS 'tiempo total'
FROM Participa
GROUP BY CodE
ORDER BY 'tiempo total' DESC LIMIT 1;
it shows me the first line of my table instead of the MAX value. However, If I make the following query:
SELECT CodE,sum(tiempo)
FROM Participa
GROUP BY CodE
ORDER BY 2 DESC LIMIT 1
I get the correct result.
I have just changed the alias 'tiempo total' for somthing that should be equivalent.
How it´s possible?
Only use single quotes for string and date constants -- never for column aliases. So:
SELECT CodE, sum(tiempo) AS `tiempo total`
FROM Participa
GROUP BY CodE
ORDER BY `tiempo total` DESC
LIMIT 1;
You are ordering by a constant string, not the name of a column. Hence, if you get the maximum in your query, it would be a total accident.
Note: You can get around these issues by giving columns names that never need to be escaped:
SELECT CodE, sum(tiempo) AS tiempo_total
FROM Participa
GROUP BY CodE
ORDER BY tiempo_total DESC
LIMIT 1;
Easier to type, too.

mysql get max number from a string field

I need to get maximum number from a part of the value that generally start with year followed by slash(/). So I need a maximum number after the slash(/) but year should be 2016
2016/422
2016/423
2016/469
2016/0470
2014/777
2015/123
2015/989
I tried this query
SELECT columname FROM tablename WHERE columname LIKE '2016/%' ORDER BY id DESC
the above query always giving '2016/469' as first record, how to get '2016/0470' as the maximum number?
any help will be much appreciated.
Thank you.
If columname follows that pattern YEAR/0000, you can use SUBSTRING function from MySQL to remove the part of the string you don't want.
SELECT value FROM (
SELECT CAST(SUBSTRING(columname, 0, 4) AS UNSIGNED) as year, CAST(SUBSTRING(columname FROM 6) AS UNSIGNED) as value FROM tablename
) total
ORDER BY year DESC, value DESC
LIMIT 1;
You need to split the string into 2 parts and evaluate them as numbers, instead of strings. The following formula will return the number after the / in the fieldname. All functions used below are described in the string functions section of the MySQL documentation. This way you can get the number after the / character, even if it is not year before the /, but sg else. The + 0 converts the string to a number, eliminating any leading 0.
select right(columnname, char_length(columnname)-locate('/',columnname)) + 0
from tablename
Just take the max() of the above expression to get the expected results.
UPDATE:
If you need the original number and the result has to be restricted to a specific year, then you need to join back the results to the original table:
select columnname
from tablename t1
inner join (select max(right(t.columnname, char_length(t.columnname)-locate('/',t.columnname)) + 0) as max_num
from tablename t
where left(t.columnname,4)='2016'
) t2
on right(t1.columnname, char_length(1t.columnname)-locate('/',t1.columnname)) + 0 = t2.max_num
where left(t1.columnname,4)='2016'
There are lots of suggestions given as answers already. But some of those seem overkill to me.
Seems like the only change needed to the OP query is the expression in the ORDER BY clause.
Instead of:
ORDER BY id
We just need to order by the numeric value following the slash. And there are several approaches, several expressions, that will get that from the example data.
Since the query already includes a condition columname LIKE '2016/%'
We can get the characters after the first five characters, and then convert that string to a numeric value by adding zero.
ORDER BY SUBSTRING(columname,6) + 0 DESC
If we only want to return one row, add
LIMIT 1
http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substring
If we only want to return the numeric value, we could use the same expression in the SELECT list, in addition columnname.
This isn't the only approach. There are lots of other approaches that will work, and don't use SUBSTRING.
Try like this:
SELECT
MAX(CAST(SUBSTRING(t.name,
LOCATE('/', t.name) + 1)
AS UNSIGNED)) AS max_value
FROM
tablename AS t;
You can try with this little uggly approach:
SELECT t.id, t2.secondNumber FROM table AS t
JOIN (SELECT id,
CONCAT(SUBSTRING(field,1,5),
if(SUBSTRING(SUBSTRING(field, 6),1,1)='0',
SUBSTRING(field, 6),
SUBSTRING(field,7)
)
) as secondNumber FROM table ) AS t2 ON t2.id=t.id
ORDER BY t2.secondNumber DESC
Would be valid only if the 0 (zeroes) before the second number (after the slash) are no more than 1.
Or if the year doesn`t matter you can try to order them only by the second number if it is ok:
SELECT t.id, t2.secondNumber FROM table AS t
JOIN (SELECT id,
if(SUBSTRING(SUBSTRING(field, 6),1,1)='0',
SUBSTRING(field, 6),
SUBSTRING(field,7)
) as secondNumber FROM table ) AS t2 ON t2.id=t.id
ORDER BY t2.secondNumber DESC

How to order selection from database alphabetically?

From this code:
SELECT *
FROM members
ORDER BY #ALPHABETICALLY
How to order it in this type?
Thanks.
If you have name column in that table the query would be:
SELECT *
FROM members
ORDER BY name ASC
SELECT ..., last_name, first_name, ...
FROM tbl
ORDER BY last_name, first_name;
VARCHAR columns in ORDER BY are sorted alphabetically; INT columns are sorted numerically.
ASC and DESC are optional suffixes for "ascending" and "descending":
`ORDER BY date DESC`
to see the latest first.
SQL queries require you to provide a column to sort on -- otherwise, your database engine would have no idea which data to use. This is an error because the behavior that would result is almost certainly not what you would be expecting!
Per your comment, you want to sort alphabetically on "name". Presuming that name is a character column, sorting on it will result in an alphabetical sort. So the query you're looking for is:
SELECT *
FROM members
ORDER BY username ASC
ASC is optional and the default; it means to sort in ascending order. To sort Z -> A, you can specify DESC instead. You can specify a different column (say, email) to sort by it instead.
SELECT *
FROM `Table_Name`
ORDER BY `Your_Column_name_1` ASC, `Your_Column_name_2` DESC

MySQL sort by not sorting?

I am fetching rows from my DB using this request:
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY 'amount' DESC
So, obviously, i expected the returned values to be sorted in descending order by the amount column in my DB, but it doesn't? it still fetches them, but just doesn't sort them?
Any ideas here? is my SQL statement wrong?
remove single quote around amount like this and try:
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC
Use below query
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC
ORDER BY clause uses column name.
Column name should not give in quotes.
there fore the query becomes as follows
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC

How to fetch the first and last record of a grouped record in a MySQL query with aggregate functions?

I am trying to fetch the first and the last record of a 'grouped' record.
More precisely, I am doing a query like this
SELECT MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)
but I'd like to get the first and the last record of the group. It could by done by doing tons of requests but I have a quite large table.
Is there a (low processing time if possible) way to do this with MySQL?
You want to use GROUP_CONCAT and SUBSTRING_INDEX:
SUBSTRING_INDEX( GROUP_CONCAT(CAST(open AS CHAR) ORDER BY datetime), ',', 1 ) AS open
SUBSTRING_INDEX( GROUP_CONCAT(CAST(close AS CHAR) ORDER BY datetime DESC), ',', 1 ) AS close
This avoids expensive sub queries and I find it generally more efficient for this particular problem.
Check out the manual pages for both functions to understand their arguments, or visit this article which includes an example of how to do timeframe conversion in MySQL for more explanations.
Try This to start with... :
Select YearWeek, Date, Min(Low_Price), Max(High_Price)
From
(Select YEARWEEK(date) YearWeek, Date, LowPrice, High_Price
From Symbols S
Where Date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)) Z
Group By YearWeek, Date
Here is a great specific solution to this specific problem:
http://topwebguy.com/first-and-last-in-mysql-a-working-solution/
It's almost as simple as using FIRST and LAST in MySQL.
I will include the code that actually provides the solution but you can look upi the whole text:
SELECT
word ,
(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated LIMIT 1) AS first_ip,
(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated DESC LIMIT 1) AS last_ip
FROM notfound GROUP BY word;
Assuming that you want the ids of the records with the lowest low_price and the highest high_price you could add these two columns to your query,
SELECT
(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,
MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)
If efficiency is an issue you should add a column for 'year_week', add some covering indexes, and split the query in two.
The 'year_week' column is just an INT set to the value of YEARWEEK(date) and updated whenever the 'date' column is updated. This way you don't have to recalculate it for each query and you can index it.
The new covering indexes should look like this. The ordering is important.
KEY yw_lp_id (year_week, low_price, id),
KEY yw_hp_id (year_week, high_price, id)
You should then use these two queries
SELECT
(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
MIN(low_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week
and
SELECT
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,
MAX(high_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week
Covering indexes are pretty useful. Check this out for more details.