SQL MAX() Function - sql

I found a very interesting/strange thing about MAX() function in SQL.
I have column ID with varchar2(20) data type, having following entries:-
ID
1
2
3
4
5
6
9
99
909
As per my understanding if i use "select max(ID) from table;" I should get 909 as the result but i get 99. Can somebody explain why this is happening?

You have misunderstood - since the column is a varchar, not numeric, it is sorted by string values; 909 comes before 99, so 99 is the maximum.
To see the maximum numeric value of your column, try:
select max(to_number(ID)) from my_table

Since the column you are using MAX on is of type VARCHAR, it is going to sort the values based on a character-by-character evaluation. It selects 99 because 9 > 0, and it will ignore the rest of the string.

Your column is being represented as characters, not numbers. So think of it as ordering these alphabetically. Alphabetically 909 will come before 99 in ascending order.

Related

How to query a varchar2 field which has numerical values using order by desc in sql

I have table with varchar 2 datatypes column now i want to fetch the records column and duration column in order by desc order but not working wat i expected.
Query :
select * from sampletable2
where code = 'C'
order by duration desc ;
QUERY output looks like below :
KeyNumber ID Code BRANCH records Duration
A907654234 4 C ALA 100 99
A875678235 3 C PHE 30 9
A123456789 1 C HIE 78 45
A907863544 5 C VAL 50 23
what i want is like :
KeyNumber ID Code BRANCH records Duration
A907654234 4 C ALA 100 99
A123456789 1 C HIE 78 45
A907863544 5 C VAL 50 23
A875678235 3 C PHE 30 9
can someone correct me where im going wrong and correct my query?
How about
order by to_number(duration) desc
It should work, if duration contains numbers. Also, if that's so, why do you keep numbers in a VARCHAR2 column?
If column contains something else, and not only numbers, then see whether regular expressions help. For example:
order by to_number(regexp_substr(duration, '\d+')) desc, duration
You can use to_number and on conversion error as follow:
order by to_number(duration default -1 on conversion error) desc
With this solution, you will get all the non number value records at last.
This answers the original version of the question.
I don't see how your query is producing the first result. But if you want to sort by numeric values, then you can convert to a number:
order by to_number(records) desc, to_number(duration) desc ;
That said, a much better approach is to fix the data model. You should not be storing numbers as strings.

How do I query a column where a specific number does not exist in any of the rows of that column

I have ID | Name | Salary with types as Integer | String | Integer respectively.
I need to query the avg of all the rows of the Salary column, and then query the avg of all the rows of the Salary column again, but if any of those rows contain 0, remove 0 from those numbers, and calculate the avg.
So like if Salary returns 1420, 2006, 500, the next query should return 142, 26, 5. Then I calculate the avg of the subsequent numbers not containing 0.
I tried googling my specific problem but am not finding anything close to a solution. I'm not looking for an answer too much more than a shove in the right direction.
My Thoughts
Maybe I need to convert the integer data type to a varchar or string then remove the '0' digit from there, then convert back?
Maybe I need to create a temporary table from the first tables results, and insert them, just without 0?
Any ideas? Hope I was clear. Thanks!
Sample table data:
ID | Name | Salary
---+----------+-------
1 | Kathleen | 1420
2 | Bobby | 690
3 | Cat | 500
Now I need to query the above table but with the 0's removed from the salary rows
ID | Name | Salary
---+----------+-------
1 | Kathleen | 142
2 | Bobby | 69
3 | Cat | 5
You want to remove all 0s from your numbers, then take a numeric average of the result. As you are foreseeing, this requires mixing string and numeric operations.
The actual syntax will vary across databases. In MySQL, SQL Server and Oracle, you should be able to do:
select avg(replace(salary, '0', '') + 0) as myavg
from mytable
This involves two steps of implicit conversion: replace() forces string context, and + 0 turns the result back to a number. In SQL Server, you will get an integer result - if you want a decimal average instead, you might need to add a decimal value instead - so + 0.0 instead of + 0.
In Postgres, where implicit conversion is not happening as easily, you would use explicit casts:
select avg(replace(salary::text, '0', '')::int) as myavg
from mytable
This returns a decimal value.
Do you just want conditional aggregation?
select avg(salary), avg(case when salary <> 0 then salary end)
from t;
or do you want division?
select id, name, floor(salary / 10)
from t;
This produces the results you specify but it has nothing to do with "average"s.

SQLite3 Order by highest/lowest numerical value

I am trying to do a query in SQLite3 to order a column by numerical value. Instead of getting the rows ordered by the numerical value of the column, the rows are ordered alphabetically by the first digit's numerical value.
For example in the query below 110 appears before 2 because the first digit (1) is less than two. However the entire number 110 is greater than 2 and I need that to appear after 2.
sqlite> SELECT digit,text FROM test ORDER BY digit;
1|one
110|One Hundred Ten
2|TWO
3|Three
sqlite>
Is there a way to make 110 appear after 2?
It seems like digit is a stored as a string, not as a number. You need to convert it to a number to get the proper ordering. A simple approach uses:
SELECT digit, text
FROM test
ORDER BY digit + 0

Selecting filtered values from Oracle using ROWNUM

I have a requirement wherein i need to find the record number of the records that are returned from the resultset. I know that i can use ROWNUM to get the record number from the resultset but my issue is slightly different. below are the details
Table : ProcessSummary
Columns:
PS_PK ProcessId StepId AsscoiateId ProcessName AssetAmount
145 25 50 Process1 3,500.00
267 26 45 Process2 4,400.00
356 27 70 Process3 2,400.00
456 28 80 90 Process4 780.00
556 29 56 67 Process5 4,500.00
656 45 70 Process6 6,000.00
789 31 75 Process7 8,000.00
Now what i need to do is fetch all the records from the ProcessSummary Table when either of ProcessId OR StepId OR AssociateId is NULL. I wrote the below query
select * from ProcessSummary where ProcessId IS NULL OR StepId IS NULL OR AsscoiateId IS NULL
As expected i got 1st, 2nd, 3rd, 6th and 7th records in the resultset that got returned.
Now what i need is to get the records numbers 1,2,3,6,7. I tried to use the ROWNUM as below but i got the values of 1,2,3,4,5 and not 1,2,3,6,7.
select ROWNUM from ProcessSummary where ProcessId IS NULL OR StepId IS NULL OR AsscoiateId IS NULL
Is it possible to get the ROWNUM values in the sequence that i want and if yes then can you please let me know how can i do this. Also if ROWNUM cannot be used then what would be the other option that i can use to get the result in the form that i want.
Any help would be greately appericiated as i could not find much on the net or SO regarding this sort of requirement.
Thanks
Vikeng21
rownum is an internal numbering that gives you a row number based on the current query results only, so that numbering is not tied to a specific record, and it will change when you change the data or the query.
But the numbering you ask for is already in your table. It looks like you just need to SELECT PS_PK .. instead. PS_PK is the field in your table that contains the actual number you want.
You can generate a numbering using an analytical function, and then filter that query. You need some fields to order by, though. In this case I've chosen PS_PK, but it can be another field, like ProcessName or a combination of other fields as well.
select
*
from
(select
dense_rank() over (order by PS_PK) as RANKING,
p.*
from
ProcessSummary p)
where
ProcessId IS NULL OR StepId IS NULL OR AsscoiateId IS NULL
So, in this query, first a numbering is calculated for each row that is returned from the inner query. The numbering is returned as the field RANKING. And then the other query filters further, but still will return the field RANKING with the original numbering.
Instead of dense_rank there is also rank and row_number. The differences are subtle, but you can just experiment and read some docs here and here to learn about the differences and see which one fits you best.
Note that this might slow down your query, because the inner query first generates a number for each row in the table (there is no filtering on that level now).

How to execute a LIKE query against a DECIMAL (or INTEGER) field?

Is it possible to execute a LIKE statement against a table column that contains DECIMAL types? Or else, what would be the best way to select matching rows given a number in a decimal (or integer) field?
E.g.:
Name Age
... ...
John 25
Mary 76
Jim 45
Erica 34
Anna 56
Bob 55
Executing something like SELECT * FROM table WHERE age LIKE 5 would return:
Name Age
John 25
Jim 45
Anna 56
Bob 55
It is not clear from your question what exactly you are trying to achieve, but based on the example query, the filtering you need to do should be achievable using normal arithmetic operators.
SELECT * FROM table WHERE MOD(age, 10) = 5 -- All records where the age ends in 5
Or:
SELECT * FROM table WHERE MOD(age, 5) = 0 -- All records where age is divisible by 5
Now that you clarified that though you are using a DECIMAL field you are not actually using it as a numeric value (as if you would, the requirement wouldn't exist), the answers given by others are reasonable - convert the field to a text value and use LIKE on it.
Alternatively, change the type of the field to something that is more suitable to the way you are using it.
You can convert your decimal field to varchar and then apply like.
If you create a query
select name from table where age like '%5%'
you could achieve this (at least in mysql and db2)
But if you prefer to match a number you should use something like:
select name from table where age > minimum and age < maximum
Or try to compare against a modulo if you are really interested in querying on the last number.