SQL - ORDER a mix of numbers and words - php

I have an SQL database with I'm calling through a php file. The column can contain both numbers and words. For example it could countain:
1
4
clowns
12
46
Naturally, ORDER BY returns:
1
12
4
46
clowns
but I would like it to sort how it would sort integers with the numbers:
1
4
12
46
clowns
Is it possible to do this?

add some new columns to solve this, first order by whether or not it is a number, then by the number value, and finally alphabetically by the word value.
In MSSQL you have access to the isnumeric function.
In ORACLE you could create a custom function using THIS
In MYSQL you could create a custom function using THIS
select your_column from(
select *,
isnumeric(your_column) as ISNUMBER,
CASE WHEN ISNUMERIC(your_column) = 1 THEN CAST(your_column AS INT) ELSE null END as NUMBERVALUE,
case when isnumeric(your_column) = 1 then null else your_column end as TEXTVALUE )
order by isnumber desc, numbervalue asc, textvalue asc
...

Related

MySQL - How to get counts of specific value from all the records

I have course table and I am storing completion status of users with 'A'. Now I want to get how many A is available from CompletionStatus field for all records.
I want this result: A = 5.
Course Table:
CourseRecordIdx User CompletionStatus
--------------- ---- --------------------
1 152 A___A_______________
2 147 AA_______A__________
I have tried with char_length but getting count with underscore and I want to get only total of A:
SELECT char_length(CompletionStatus) FROM `course` where CourseRecordIdx = 36
Any idea how to get result with select query?
Thanks.
You can try with this simplest way:
SELECT length(REPLACE("field_name","_","")) FROM `tbl_name`;
You can use LENGTH and REPLACE for that purpose :
SELECT LENGTH(CompletionStatus) - LENGTH(REPLACE(CompletionStatus, 'A', '')) as count_Char
FROM `course`
This basically counts how many characters are in that string, and then checks the difference between that number, and the number of characters with out the specific character.
I suppose the following will work, first replace all _ with ''.
After that use char_length() function.
SELECT CHAR_LENGTH(REPLACE(CompletionStatus,'_','') as totalA FROM course where CourseRecordIdx = 36;
You can write this query for this:
SELECT CourseRecordIdx,User,CompletionStatus,
ROUND (
(
LENGTH(CompletionStatus)- LENGTH( REPLACE ( CompletionStatus, "A", ""))
) / LENGTH("A")) AS count
from `course` where CourseRecordIdx = 36

sorting max to min value in sql is not working properly

i have 1 table for ex table1
and it have columns names: id, name, amount.
id name amount
1 abc 20
2 xyz 50
3 pqr 246
i want to sort it from max value to min.
i have written this query:
SELECT * FROM table1 ORDER BY amount DESC;
but it gives output like this:
id name amount
2 xyz 50
3 pqr 246
1 abc 20
which is not valid output that i want, i want output like this:
id name amount
3 pqr 246
2 xyz 50
1 abc 20
so, if anyone know the solution of this problem please give me the solution.
You are storing the amount as a string, it would appear.
Here are two solutions. You can convert the values to a number for the sort:
order by amount + 0 desc
Or, order by the length first and then the value:
order by length(amount) desc, amount desc
In general, in SQL, you should make use of the built-in types and store values as the appropriate time. Numbers should be stored as numbers (integers, floats, or decimals). Dates and times should be stored as date/time types. And strings can be used for string values.
Its related to wrong datatype.
Make data type of amount column as INT or FLOAT.
See the design of the table by using a command such as
DESC TABLENAME
I suspect your Amount column is text/varchar and not numeric.
Or simply run the following command and then try your query.
ALTER TABLE TABLE1 ALTER COLUMN AMOUNT INT
Always use appropriate data types for the data to store.
Since the data type of amount column is string and not numeric, ORDER BY sorts it based on the ASCII Value.
SQL> WITH DATA(ID, NAME, amount) AS(
2 SELECT 2, 'xyz', '50' FROM dual UNION ALL
3 SELECT 3, 'pqr', '246' FROM dual UNION ALL
4 SELECT 1, 'abc', '20' FROM dual
5 )
6 SELECT * FROM DATA
7 ORDER BY amount DESC;
ID NAM AMO
---------- --- ---
2 xyz 50
3 pqr 246
1 abc 20
SQL>
If you have only numeric data stored as string, then you could use TO_NUMBER to explicitly convert the string into number while sorting.
ORDER BY to_number(amount) DESC
For example,
SQL> WITH DATA(ID, NAME, amount) AS(
2 SELECT 2, 'xyz', '50' FROM dual UNION ALL
3 SELECT 3, 'pqr', '246' FROM dual UNION ALL
4 SELECT 1, 'abc', '20' FROM dual
5 )
6 SELECT * FROM DATA
7 ORDER BY to_number(amount) DESC;
ID NAM AMO
---------- --- ---
3 pqr 246
2 xyz 50
1 abc 20
SQL>

Select 2-3 number combination from 5 column Table MySQL

Table structure:
MyTable (
ID INT AUTO_INCREMENT,
Num1 INT,
Num2 INT,
Num3 INT,
Num4 INT,
PRIMARY KEY(ID)
)engine=InnoDB;
Now i have around 20-30k records. Num1, Num2, Num3 and Num4 are just some random numbers. Im trying to select 2 and 3 number combinations from this table. For example lets say i have the following rows in table:
ID Num1 Num2 Num3 Num4
1 20 11 9 150
2 30 11 20 19
3 40 45 11 20
I would want to select the most frequently used 2 number combinations and then 3 number combinations. So note that 20 and 11 appear 3 times in table means the combination 20,11 or 11,20 doesnt matter the order has count 3 and so on for other combinations.
I want to retrieve this data in PHP array so that i can do some calculations or display on screen.
What i tried so far:
SELECT *
FROM MyTable
WHERE (Num1 = :num1 AND Num2 = :num2) OR (Num1 = :num1 AND Num3 = :num2) OR
(Num1 = :num1 AND Num4 = :num2) OR (Num2 = :num1 AND Num1 = :num2) OR
(Num2 = :num1 AND Num3 = :num2) OR (Num2 = :num1 AND Num4 = :num2) OR
***
***
and so on for all combinations. Now this gets annoying if i try to use it for 3 number combinations.
Is there a better and efficient way of doing this?
Do i need to restructure table to make this easier?
Will restructured table be normalized? (Right now i think is normalized if not please tell me)
Case 2 combinations
I think you should consider store information in a big matrix like this:
num times_appearing_with_number_1 times_appearing_with_number_2 ...
For a case like
1 8 2 3
1 7 23 24
it would be like:
num 1 2 3 4 5 6 ...
1 - 1 1 0 0 0 ...
2 1 - 1 0 0 0 ...
And then you check which lines have bigger numbers. The indexes would be useful to get the number it corresponds to.
Case 3 combinations
The same with a 3D-matrix.
To feed these tables you should only fetch the information from MySQL and then loop.
since the order of values doesn't matter, there are only 6 permutations to pick two out of four columns (c1-c2, c1-c3, c1-c4, c2-c3, c2-c4 and c3-c4), and only four permutations to pick three (c1-c2-c3, c1-c2-c4, c1-c3-c4, c2-c3-c4).
One approach would be to create a temporary table which contains the id of the row and all 6 (4 for three cols) permutations of those values. You could use a query like this:
SELECT id, CASE Num1<=Num2 WHEN TRUE THEN CONCAT(Num1,"-",Num2) ELSE CONCAT(Num2,"-",Num1) END FROM MyTable
UNION
SELECT id, CASE Num1<=Num3 WHEN TRUE THEN CONCAT(Num1,"-",Num3) ELSE CONCAT(Num3,"-",Num1) END FROM MyTable
...
All that's left then is counting the number of matching rows (note that above query could either be run manually or as a subquery to the counting query)
Edit: Something to fiddle with.

algorithm/query to get statistical data from table using php/mysql

I have the following table structure:
CREATE TABLE test(
myID INT,
num1 INT,
num2 INT,
num3 INT,
PRIMARY KEY (myID)
)engine=innodb;
now i have the following data in the table:
myID num1 num2 num3
1 15 27 98
2 27 38 66
3 15 27 77
now i need to run 2 queries, first query runs to select all numbers and on PHP side i count the number of times each number appeared (frequencies), the second query should select the second most frequent number.
First query:
$numfreq = PDO->prepare('
SELECT num1, num2, num3
FROM test
');
$numfreq->execute();
$allNums = array();
while ($row = $numfreq->fetch(PDO::FETCH_ASSOC)) {
$allNums[] = intval($row['num1']);
$allNums[] = intval($row['num2']);
$allNums[] = intval($row['num3']);
}
$numFrequencies = array_count_values($allNums);
arsort($numFrequencies);
this correctly returns frequencies of each number from the table. Now for the second part
THIS IS WHERE I NEED HELP:
I get the most frequent appeared number in this case its 27 since its frequency is 3, I need to select that 1 number that appears the most next to 27 means i need to get somehow number 15 since it appears twice next to 27.
i can probably figure out algorithm on PHP side but i was wondering if its possible to do it using query?
so the final result would be:
most frequent number: 27
most frequent number 27 combined with 15 appears 2 times and is most frequent combination.
select val, count(val) as frequency
from
(select num1 as val from test
union all
select num2 as val from test
union all
select num3 as val from test
) as b
group by val
order by frequency desc
limit 2
Sqlfiddle here.
The inner query converts the three columns into a result set with just one column - highlight the inner query, and you'll see how it works. We then use that result set as the source for the counting/ordering query.

Retriving an array of grouped elements in mysql (+php)

I need i bit of help with this query, so far i have this:
SELECT * FROM coupons WHERE discount_id = '1' AND client_username = 'Zara' GROUP BY winner_id
The table is like this
id client_username winner_id bdate discount_id destroyed
72 zara 1125405534 2012-11-11 03:34:49 4 0
71 zara 1125405534 2012-11-11 03:34:43 1 0
70 zara 1125405534 2012-11-11 03:34:27 1 0
I want to group the result by winner_id (its a unique user id) where discount_id is equal to some value and order by bdate, the think is I need the id bdate and destroyed value of each ocurrence of the user and also count the number of times winner_id appear, so the result needs to be a value (count of how many times winner_id appears), and 3 arrays (discount_id,destroyed,id).. But I have no idea how to retrive this in the way I need. Thanks for any help!
Two basic methods:
aggregate in mysql and "explode" in php
aggregate in PHP
number 1 involves using some aggregate functions in your query, like COUNT() and GROUP_CONCAT():
SELECT count(*) as num_wins, GROUP_CONCAT(discount_id, ',') as discount_ids ...
then in PHP, these GROUP_CONCAT columns can be "exploded" into arrays while looping over the results:
foreach($rows as $row) {
$discount_ids = explode(',', $row['discount_ids']);
// ...
}
number 2 is easier SQL, but uglier PHP. Basically just select all your rows, and then pre-process the results yourself. (I recommend the previous solution)
foreach($rows as $row) {
$results_tree[$row['winner_id']]['num_wins']++;
$results_tree[$row['winner_id']]['discount_ids'][] = $row['discount_id'];
// ...
}

Categories