MYSQL Letters before numbers descending - mysql

I am trying to get letters before numbers with a descending order and am finding it very difficult to do so.
I have tried using Case ordering
ORDER BY CASE WHEN ' . $this->sortbycast . ' LIKE \'%[a-z]%\' THEN 0 WHEN ' . $this->sortbycast . ' LIKE \'%[0-9]%\' THEN 1 ELSE ' . $this->sortbycast . ' END DESC
Regular expression as follows
' ORDER BY ' . $this->sortbycast . ' REGEXP \'^[a-z]\', ' . $this->sortbycast . ' desc';
and CAST()
' ORDER BY CAST(' . $this->sortbycast . ' AS UNSIGNED), ' . $this->sortbycast;
But none of these have had the desired result. All work correctly with ascending order. Any help would be appreciated. Thanks.
Update due to Strawberry's response
DB Fiddle here
My present query looks like this - reformatted for legibility:
SELECT p.*
, m.data
, m.id author_id
FROM anchor_posts p
JOIN anchor_post_meta m
ON m.post = p.id
WHERE p.category = 5
AND m.extend = 3
ORDER
BY CAST('anchor_post_meta.data' AS UNSIGNED) -- NOTE: THIS IS A STRING !?!
, m.data DESC
LIMIT 12;
The desired result
The desired result would be to have items show in the following order:
data
==============
A Title
B Title
C Title
D Title
70000
60000
45000
30000
25000
12000
Please see the following version of the DB Fiddle to see more clearly.

Related

MySQL, Finding every string/words frequency in a column

I want to find every word frequency in a column by using MySQL only (if possible). For example:
Table:
id message
1 I want to eat pizza
2 I wanted chocolates
3 He doesn't like me
Query: ???
Result:
Word Frequency
I 2
want 1
to 1
eat 1
pizza 1
wanted 1
etc..
Is it possible? If so please help, thank you
You need to split the data. This is a pain:
select substring_index(substring_index(message, ' ', n.n), ' ', -1) as word,
count(*)
from (select 1 as n union all select 2 union all select 3 union all
select 4 union all select 5
) n join
t
on n.n <= 1 + length(message) - length(replace(message, ' ', ''))
group by word;
The above assumes that all messages are five words or less. You can extend the number in the first subquery for longer messages.
Here is a php example. You will probably have to tweak it a bit.
lets assume you have a word_frequency table with a unique column word and an integer for count. Also, this is susceptible to SQL injection, so you should be careful. But this should get you started.
<?php
$con=mysqli_connect("localhost","my_user","my_password","my_db");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$results = mysqli_query($con,"SELECT message FROM table1");
while($row = $results->fetch_assoc()) {
$words = explode(" ", $row['message']);
foreach ($words as $word) {
mysqli_query($con,"INSERT INTO word_frequency (`word`,`count`) VALUES ('$word',1) ON DUPLICATE KEY UPDATE `count`=`count`+1;");
}
}
mysqli_close($con);

How can I extract a last name from full name in mysql?

I have a table with fullname column. I want to make a query for finding a person via his last name but his last name is in the full name column.
Would it matter if it accidentally returned someone whose first name matched your query?
A simple query would be:
SELECT *
FROM TABLE
WHERE fullname LIKE '%insertlastname%'
If you want to define the last name as the name after the last space:
SELECT substring_index(fullname, ' ', -1) as lastname
FROM TABLE
WHERE lastname='insertlastname'
Two suboptimal answers, but some answers at least.
enter code here You can use this if you want to fetch by query:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX( `fullname` , ' ', 2 ),' ',1) AS b,
SUBSTRING_INDEX(SUBSTRING_INDEX( `fullname` , ' ', -1 ),' ',2) AS c FROM `users` WHERE `userid`='1'
But you can also try by PHP to fetch last name. You just use explode function to fetch last name.
Exm:
$full_name = "row moin";
$pieces = explode(" ", $fullname);
echo $first_name = $pieces[0]; // row
echo $last_name = $pieces[1]; // moin
A simple answer for this is like this suppose we have a name
Charles Dickens
:
SELECT * FROM TABLE_NAME WHERE SUBSTRING_INDEX(FULLNAME,' ',-1) like '%Dickens';

How to add 'AND' parts to Joomla Jdatabase query?

I need to write an db query based on the Joomla jdatabase format, but I get stuck with writing the 2 'AND' parts for the native sql query below (I could not figure it out based on http://docs.joomla.org/Selecting_data_using_JDatabase).
How to include the 2 AND parts? Appreciate your help
//get userid of collective based on entered collective name, and get productid based on entered productname
//NATIVE MYSQL:
SELECT #__users.id, #__products.productid
FROM #__users INNER JOIN #__products
ON #__users.id = #__products.owner
AND #__users.name = $form_username
AND #__products.productname = $form_productname;
What I have sofar:
//Joomla Jdatabase query sofar:
$query
->select($db->quoteName(array('a.id', 'b.productid')))
->from($db->quoteName('#__users', 'a'))
->join('INNER', $db->quoteName('#__products', 'b') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.owner') . ') ') //HERE I think some AND parts need to be included in some way?
->order($db->quoteName('a.created') . ' DESC');
I haven't tested this so please let me know if it works and if not, I will come back with an edit
->join('INNER', $db->quoteName('#__products', 'b') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.owner') . ')
AND ' . $db->quoteName('#__users.name') . ' = ' . $form_username . '
AND ' . $db->quoteName('#__products.productname') . ' = ' . $form_productname)

count characters matching in CONCAT MySQL REGEXP

I have the following MySQL query which works
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
Now there is no ORDER BY and if:
- bigDataField contains "one" this field is shown
- bigDataField contains "one two" this field is shown aswell
now it depends on the id which one of those is shown first, but I want the one with the more matches to be shown first!
I tried with
SUM(
CASE WHEN bigDataField REGEXP "one|two"
THEN 1
ELSE 0 END
) AS matches
But that does not work. Can anyone help me. I think the best would be as the title says to count the matching charachters from the REGEXP. If there are other ways please explain.
The REGEXP is a user input, so, I'm trying to implement a small search over a small Database.
This is theoretical whilst sqlfiddle is down but you might have to split the REGEXP into two so you can count the matches. REGEXP will return either a 0 or 1. Either it matched or didn't. There's no support for finding how many times it was matched in a string.
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
ORDER BY (bigDataField REGEXP "one" + bigDataField REGEXP "two") DESC
There is no way to count the amount of matches on a regex. What you can do is match them separately and order by each of those matches. EG:
SELECT *,
CONCAT( office, ' ', contactperson ) AS bigDataField
FROM webcms_mod_references
HAVING bigDataField REGEXP "one|two"
ORDER BY
CASE WHEN bigDataField REGEXP "one" AND bigDataField REGEXP "two" THEN 0
ELSE 1 -- The else should catch the "two" alone or the "one" alone because of the filtering
END
Of course, you can use a LIKE here too but maybe your regex are more complex than that :)
When I want to count some substring I do replace and "-" the length, example:
SELECT (
LENGTH('longstringlongtextlongfile') -
LENGTH(REPLACE('longstringlongtextlongfile', 'long', ''))
) / LENGTH('long') AS `occurrences`
I think this is an elegant solution for a problem of counting how many times 'long' appears inside provided 'string'
This is not especially the answer to this question, but I think strongly attached to it... (And I hope, will help someone, who cames from google, etc)
So if you use PHP (if not, may dont keep reading ...), you can build the query with that, and in this case, you can do this (about #Moob great answer):
function buildSearchOrderBy(string $regex, string $columName, string $alternateOrderByColumName): string
{
$keywords = explode ('|', $regex);
if (empty ($keywords)) {
return $alternateOrderByColumName;
}
$orderBy = '(';
$i = 0;
foreach ($keywords as $keyword) {
$i++;
if ($i > 1) $orderBy .= " + ";
$orderBy .= "IF((" . $columName . " REGEXP '" . $keyword . "')>0, " . (100 + strlen($keyword)) . ", 0)";
}
$orderBy .= ')';
return $orderBy;
}
So in this case every match worth 100 + so many scores, what the numbers of the characters in the current keyword. Every match starting from 100, because this ensure the base, that the first results will be these, where the total score originate from the more matches, but in proportionally worth more a longer keyword in any case.
Builded to one column check, but I think you can update easy.
If copied to your project, just use like this (just an example):
$orderBy = buildSearchOrderBy($regex, 'article.title', 'article.created');
$statement = "SELECT *
FROM article
WHERE article.title REGEXP '(" . $regex . ")'
ORDER BY " . $orderBy . " DESC"
;

Sorting in mysql

I have a column abc in table t1. The column has values
A1
A2
A3
A4
.
.
A12
B1
B2
.
.
.
B12
C1
C2
.
.
.
C12
H1
.
.
H12
I wanna sort them such that the output is
A1
B1
C1
.
.
H1
A2
B2
C2
.
.
.
H2
.
.
.
.
A12
.
.
.
H12
A select * from abc statement gives A1,A10,A2.... as output. I am trying to use SUBSTR but haven't gotten it right.
This should do it;
SELECT * FROM TEST
ORDER BY SUBSTRING(VALUE, 2) + 0,
SUBSTRING(VALUE, 1, 1);
Demo here.
Considering the format is always a single alpha char followed by any number of digits:
ORDER BY RIGHT(colname, LENGTH(colname)-1)
maybe this:
ORDER BY LEFT(colname,1), RIGHT(colname, LENGTH(colname)-1)
order by lpad(date_created,1,0) ASC
#bfavaretto i think if you use -1 in length colname, and you have 3 characters like in example you will have some strange results.
SELECT Square
FROM Table1
ORDER BY
CASE WHEN Square REGEXP '^[A-Z]{2}'
THEN 1
ELSE 0
END ASC,
CASE WHEN Square REGEXP '^[A-Z]{2}'
THEN LEFT(Square, 2)
ELSE LEFT(Square, 1)
END ASC,
CASE WHEN Square REGEXP '^[A-Z]{2}'
THEN CAST(RIGHT(Square, LENGTH(Square) - 2) AS SIGNED)
ELSE CAST(RIGHT(Square, LENGTH(Square) - 1) AS SIGNED)
END ASC