Ignore case in ORDER BY in mysql - mysql

I came across a situation where i want to sort the mysql query result in alphabetical order ignoring the case... I mean
Al
aasd
Cfds
ddafsf
...
I found a solution where convert every element of the result into either lower or upper case and use Order By ..I didnt like this approach... http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html .. Read this article..... But i grasped nothing...Just wanna know how can this be done... cheers...

why not use ASC directly,
SELECT *
FROM tableName
ORDER BY columnName ASC

Related

MySQL 5.7 RAND() and IF() without LIMIT leads to unexpected results

I have the following query
SELECT t.res, IF(t.res=0, "zero", "more than zero")
FROM (
SELECT table.*, IF (RAND()<=0.2,1, IF (RAND()<=0.4,2, IF (RAND()<=0.6,3,0))) AS res
FROM table LIMIT 20) t
which returns something like this:
That's exactly what you would expect. However, as soon as I remove the LIMIT 20 I receive highly unexpected results (there are more rows returned than 20, I cut it off to make it easier to read):
SELECT t.res, IF(t.res=0, "zero", "more than zero")
FROM (
SELECT table.*, IF (RAND()<=0.2,1, IF (RAND()<=0.4,2, IF (RAND()<=0.6,3,0))) AS res
FROM table) t
Side notes:
I'm using MySQL 5.7.18-15-log and this is a highly abstracted example (real query is much more difficult).
I'm trying to understand what is happening. I do not need answers that offer work arounds without any explanations why the original version is not working. Thank you.
Update:
Instead of using LIMIT, GROUP BY id also works in the first case.
Update 2:
As requested by zerkms, I added t.res = 0 and t.res + 1 to the second example
The problem is caused by a change introduced in MySQL 5.7 on how derived tables in (sub)queries are treated.
Basically, in order to optimize performance, some subqueries are executed at different times and / or multiple times leading to unexpected results when your subquery returns non-deterministic results (like in my case with RAND()).
There are two easy (and likewise ugly) workarounds to get MySQL to "materialize" (aka return deterministic results) these subqueries: Use LIMIT <high number> or GROUP BY id both of which force MySQL to materialize the subquery and return the expected results.
The last option is turn off derived_merge in the optimizer_switch variable: derived_merge=off (make sure to leave all the other parameters as they are).
Further readings:
https://mysqlserverteam.com/derived-tables-in-mysql-5-7/
Subquery's rand() column re-evaluated for every repeated selection in MySQL 5.7/8.0 vs MySQL 5.6

ORDERBY "human" alphabetical order using SQL string manipulation

I have a table of posts with titles that are in "human" alphabetical order but not in computer alphabetical order. These are in two flavors, numerical and alphabetical:
Numerical: Figure 1.9, Figure 1.10, Figure 1.11...
Alphabetical: Figure 1A ... Figure 1Z ... Figure 1AA
If I orderby title, the result is that 1.10-1.19 come between 1.1 and 1.2, and 1AA-1AZ come between 1A and 1B. But this is not what I want; I want "human" alphabetical order, in which 1.10 comes after 1.9 and 1AA comes after 1Z.
I am wondering if there's still a way in SQL to get the order that I want using string manipulation (or something else I haven't thought of).
I am not an expert in SQL, so I don't know if this is possible, but if there were a way to do conditional replacement, then it seems I could impose the order I want by doing this:
delete the period (which can be done with replace, right?)
if the remaining figure number is more than three characters, add a 0 (zero) after the first character.
This would seem to give me the outcome I want: 1.9 would become 109, which comes before 110; 1Z would become 10Z, which comes before 1AA. But can it be done in SQL? If so, what would the syntax be?
Note that I don't want to modify the data itself—just to output the results of the query in the order described.
This is in the context of a Wordpress installation, but I think the question is more suitably an SQL question because various things (such as pagination) depend on the ordering happening at the MySQL query stage, rather than in PHP.
My first thought is to add an additional column that is updated by a trigger or other outside mechanism.
1) Use that column to do the order by
2) Whatever mechanism updates the column will have the logic to create an acceptable order by surrogate (e.g. it would turn 1.1 into AAA or something like that).
Regardless...this is going to be a pain. I do not evny you.
You can create function which have logic to have human sort order like
Alter FUNCTION [dbo].[GetHumanSortOrder] (#ColumnName VARCHAR(50))
RETURNS VARCHAR(20)
AS
BEGIN
DECLARE #HumanSortOrder VARCHAR(20)
SELECT #HumanSortOrder =
CASE
WHEN (LEN(replace(replace(<Column_Name>,'.',''),'Figure ',''))) = 2
THEN
CONCAT (SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),1,1),'0',SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),2,2))
ELSE
replace(replace(<Column_Name>,'.',''),'Figure ','')
END
FROM <Table_Name> AS a (NOLOCK)
WHERE <Column_Name> = #ColumnName
RETURN #HumanSortOrder
END
this function give you like 104,107,119,10A, 10B etc as desired
And you can use this function as order by
SELECT * FROM <Table_Name> ORDER BY GetHumanSortOrder(<Column_Name>)
Hope this helps

SELECT value AS (desc) not working in subquery

As(no pun intended) you can see in this screenshot the AS statement is not changing the title of the returned query when the AS is located in the subquery.
The right side of the picture is my exp_tables table. The goal here is to figure out what level the player is in each specific skill(so in my Java application I can put it in a nice progressbar). Please let me know if there is something wrong with my SQL for the AS, or if you want to be really helpful, let me know if there is a better way I should be doing this. Thanks so much for your help. Love this site; hoping I can be smart enough to help others soon.
EDIT
Yes sorry for forgetting to upload the code >.<
SELECT
skill_alchemy_exp, ((SELECT exp_tables.id AS alchemy_lvl FROM exp_tables WHERE skill_alchemy_exp < tradeskills LIMIT 1)-1),
skill_axes_exp, ((SELECT exp_tables.id AS axes_lvl FROM exp_tables WHERE skill_axes_exp < weapons LIMIT 1)-1),
skill_baking_exp,((SELECT exp_tables.id AS baking_lvl FROM exp_tables WHERE skill_baking_exp < tradeskills LIMIT 1)-1),
skill_blacksmithing_exp,((SELECT exp_tables.id AS blacksmithing_lvl FROM exp_tables WHERE skill_blacksmithing_exp < tradeskills LIMIT 1)-1),
skill_blocking_exp, skill_blunts_exp, skill_bows_exp, skill_carpentry_exp, skill_cooking_exp,
skill_crossbows_exp, skill_daggers_exp, skill_dark_exp, skill_earth_exp, skill_fire_exp,
skill_foraging_exp, skill_harvesting_exp, skill_healing_exp, skill_hiding_exp, skill_holy_exp,
skill_looting_exp, skill_luck_exp, skill_lumberjacking_exp, skill_milling_exp, skill_mining_exp,
skill_planting_exp, skill_polearms_exp, skill_smelting_exp, skill_swords_exp, skill_wands_exp,
skill_wind_exp
FROM kisnard.characters
WHERE name='Proskier'
Using the "AS" operator on a column inside a sub-query doesn't give an entire sub-query a name. If you look at the left hand part of the picture, you'll notice the column names of the sub-selects are the selects themselves because you didn't give those "columns" a name.
It's hard to tell exactly what it is you're trying to achieve, but you can do something like this... which might be what you want:
SELECT a, b, (SELECT xyz FROM ...) AS c, d, e, ...
That lets you give an alias to the sub-query.

mysql group_concat in where

I am having a problem with the following query(if this is a duplicate question then i'm terribly sorry, but i can't seem to find anything yet that can help me):
SELECT d.*, GROUP_CONCAT(g.name ORDER BY g.name SEPARATOR ", ") AS members
FROM table_d AS d LEFT OUTER JOIN table_g AS g ON (d.eventid = g.id)
WHERE members LIKE '%p%';
MySQL apparently can't handle a comparison of GROUP_CONCAT columns in a WHERE clause.
So my question is very simple. Is there a workaround for this, like using sub-query's or something similar? I really need this piece of code to work and there is not really any alternative to use other than handling this in the query itself.
EDIT 1:
I won't show the actual code as this might be confidential, I'll have to check with my peers. Anyway, I just wrote this code to give you an impression of how the statement looks like although I agree with you that it doesn't make a lot of sense. I'm going to check the answers below in a minute, i'll get back to you then. Again thnx for all the help already!
EDIT 2:
Tried using HAVING, but that only works when i'm not using GROUP BY. When I try it, it gives me a syntax error, but when I remove the GROUP BY the query works perfectly. The thing is, i need the GROUP BY otherwise the query would be meaningless to me.
EDIT 3:
Ok, so I made a stupid mistake and put HAVING before GROUP BY, which obviously doesn't work. Thanks for all the help, it works now!
Use HAVING instead of WHERE.
... HAVING members LIKE '%peter%'
WHERE applies the filter before the GROUP_CONCAT is evaluated; HAVING applies it later.
Edit: I find your query a bit confusing. It looks like it's going to get only one row with all of your names in a single string -- unless there's nobody in your database named Peter, it which case the query will return nothing.
Perhaps HAVING isn't really what you need here...
Try
SELECT ...
...
WHERE g.name = 'peter'
instead. Since you're just doing a simple name lookup, there's no need to search the derived field - just match on the underlying original field.
GROUP_CONCAT is an aggregate function. You have to GROUP BY something. If you just want all the rows that have %peter% in them try
SELECT d.*, g.name
FROM table_d AS d
LEFT OUTER JOIN table_g AS g
ON (d.eventid = g.id)
WHERE g.name LIKE '%peter%';

Is possible to do this with a single query: get a fixed number of items of different types, ordered

Let's say i have a table with a "type" and a "date" column, and i want to fetch the latest 3 items of each type, ordered by date.(Can't trust the natural table order, or insertion order).
The query doesnt need to calculate all the different values for the "type" column, that can be specified in the query.
I'm trying with variables, like this:
set #c=0;
set #d=0;
select *, #c:=IF(type = 1, #c+1,#c), #d:=IF(type = 2, #d+1,#d) from testtable HAVING((type=1 AND #c < 3) OR (type=2 AND #d<3)) order by testdate;
This is "almost" working, (it's returning one more entry for each type,which is fine), and i guess it's related to way mysql is resolving the HAVING clause (in fact, in some scenarios i'm finding i need to use WHERE instead of HAVING).Can someone shed some light in this? Am i safe using it like this?
Ok, looks that using HAVING is fine...I was having problems because, in my real code, i need to use a few order-by, and the last of those is RAND() (to resolve ties), and that RAND() ordering seems to mess up with the mysql variable assignment.