I have a data in the table in the form below and it is in varchar(8) datatype
Total
100
101
104.5
88
1038
64
108.3
10872
900
I like to use ASC in T-sql so that I can display it into ascending order, however I
cannot do it as it is in varchar(8) form
For example
select Total from
Table A
Order by Total ASC
How to first add these values into Temporary temp table?
and How to convert this varchar(8) values and into what? so that
you can display them in ASC or ascending order using T-SQL query?
Anyone?
You could cast the value like this.
SELECT
Total
FROM Table A
ORDER BY CAST(Total AS FLOAT) ASC
You may lose data converting back to float.
So here is a varchar based sort.
DECLARE #badDesign TABLE (floatcol varchar(8) NOT NULL);
INSERT #badDesign VALUES ('100'),('101'),('104.5'),('88'),('1038'),('64'),('108.3'),('10872'),('900'),('108'), ('108.32'), ('108.4')
SELECT *
FROM #badDesign
ORDER BY
RIGHT('00000000' +
CASE
WHEN CHARINDEX('.', floatcol) = 0 THEN floatcol
ELSE LEFT(floatcol, CHARINDEX('.', floatcol)-1)
END
, 8),
CASE
WHEN CHARINDEX('.', floatcol) = 0 THEN '.0'
ELSE SUBSTRING(floatcol, CHARINDEX('.', floatcol)+1, 8)
END
The values from your example looks like float numbers. So
1) Since they all have no more than 8 digits, you can cast it to float(53) (it has about 15 decimal digits precision) without loss of data. Or to decimal(15,7) to be completely sure.
2) Generally it's strange to store float values as strings in the database.
Use CAST or CONVERT functions, e.g.:
select Total from
Table A
Order by CAST(Total as float) ASC
Reference: http://msdn.microsoft.com/en-us/library/ms187928.aspx
Unless you want to keep the converted values, you don't need to store it in a temporary table. Just convert them for the sorting:
select Total
from [Table A]
order by cast(Total as float)
(Ascending is the default way to sort, so you don't have to specify that.)
Related
I am trying to convert date to number like below, not sure which function works better.
Database used is SQL Server.
Table details
create table test
(
id varchar(255),
call_date varchar(255)
);
insert into test('26203', '14-Aug-2020');
I need output as 4405726203 -- its concatenation of date (14-Aug-2014) + id (26203)
This is too long for a comment.
SQL Server allows you to convert a datetime to a float. That would be:
select cast(dte as float)
from (values (convert(datetime, '14-Aug-2020'))) v(dte)
However, the corresponding floating point value is 44055 (https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d142a64db0872e7572eb4fbd6d5d5fe7). It is a bit of mystery what your intention is.
You could subtract 2, but that seems arbitrary. You could calculate the number of days since 1899-12-30. But that also seems arbitrary.
In any case, once you figure out how to convert the date to the number you want, just use concat() to combine the values.
I have found the solution:
convert(varchar,CAST(CONVERT(datetime,call_date) as bigint)) + id
Under the hood, a SQL Server DateTime is a tuple of 2 32-bit integers:
The first integer is a count of days since since the epoch, which for SQL Server is 1 January 1900
The second integer is a count of milliseconds since start of day (00:00:00.000). Except that the count ticks up in 3- or 4-milliscond increments. Microsoft only knows why that decision was made.
You can get the count of days since the epoch with
convert( int, convert( date, t.call_date ) )
[wrap that in convert(varchar, ... ) to turn it into a string]
Looks like your id is already a varchar, so you can say:
select compound_key = convert(varchar,
convert(int,
convert(date,
call_date
)
)
)
+ t.id
from test t
I would suggest padding both fields with leading zeros to a fixed length so as to avoid possible collisions (assuming you're trying to generate a key here). Signed 32-bit integer overflows a 2.1 billion-ish, so 9 digits for each field is sufficient.
This works
select concat(datediff(d, 0, cast(call_date as date)), id)
from
(values ('26203','14-Aug-2020')) v(id, call_date);
Results
4405526203
I've got a column that shows the date as a decimal such as 101118 for 10-11-18 and 90118 for 09-01-18. I am trying to create a simple report that would give me all reservations yesterday.
So for example
Select playerid, datereservationmade
from dbo.lms
normally there is very simple and I would just do
Select playerid, datereservationmade
from dbo.lms
where datereservationmade >= dateadd(day,datediff(day,1,GETDATE()),0)
AND datereservationmade < dateadd(day,datediff(day,0,GETDATE()),0)
That does not work in this case because the datereservationmade field is a decimal and if its a month 1-9 it leaves off the 0 and makes it a 5 digit decimal then if its 10-12 it is a 6 digit decimal.
Someone please help me figure out how to convert this!
If at all possible, you really should fix your schema so that dates are actually being stored as dates.
If you need to work with the decimal data type, you can use something like the following...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
BEGIN DROP TABLE #TestData; END;
CREATE TABLE #TestData (
decimal_date DECIMAL(6, 0) NOT NULL
);
INSERT #TestData (decimal_date) VALUES (101118), (90118), (101718);
--==============================================
SELECT
td.decimal_date,
dd.date_date
FROM
#TestData td
CROSS APPLY ( VALUES (RIGHT('0' + CONVERT(VARCHAR(6), td.decimal_date), 6)) ) cd (char_date)
CROSS APPLY ( VALUES (CONVERT(DATE, STUFF(STUFF(cd.char_date, 5, 0, '/'), 3, 0, '/'), 1)) ) dd (date_date)
WHERE
dd.date_date = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()));
Convert the decimal to varchar(6) by adding a zero in front and getting the RIGHT 6 characters.
Then convert the string to a date from its parts, which are substrings in your varchar(6). This is made easier in SQL Server 2012 with the DATEFROMPARTS function.
Using the DATEFROMPARTS, as Tab Alleman suggested, you might get something like this:
-- Example of the arithmetic
SELECT 101118 / 10000 AS Month, (101118 % 10000) / 100 AS Day, (101118 % 100) AS Year
-- Using the math in DATEFROMPARTS
SELECT DATEFROMPARTS((101118 % 100) + 2000, 101118 / 10000, (101118 % 10000) / 100 )
However, I'm skeptical that you've provided all the correct information. What happens on January first? Your decimal value won't start with zero (as you stated). Will your day always pad with zero? If not, then 1119 won't produce the same result as 10119. If, however, your day does start with zero, then the equation above should work fine.
I currently have a column in db with few ranges storaged as varchar, such as:
0-499
1000-1199
500-999
How do I order these ranges like the following:
0-499
500-999
1000-1199
Thanks in advance
If you want to be tricky, you can do:
order by cast(replace(col, '-', '.') as decimal(30, 15))
This replaces the hyphen with a decimal point, converts to a numeric value, and uses that for sorting. This should work in just about any database.
This is not perfect, because it does not really order by the second number of the range correctly. But the first number would need to exactly match (and for some reason, that seems unlikely to me base on your sample data).
Order by the characters before the hyphen, converted to an integer.
You can useorder by clause with left() function :
order by cast(left(n, charindex('-', n)-1) as int);
However, the preceding order by cluase has int conversation, if you have decimal value before hyphen then use decimal instead
if these are the only values:
order by
case varcharcol when '0-100' then 1
when '500-1000' then 2
when '1000-1199' then 3
end
create table #temp1(id int,range varchar(50))
insert into #temp1(id,range)
values (1,'0-499'),(2,'1000-1199'),(3,'500-999')
select * from #temp1 order by cast(replace(range, '-', '.') as decimal(30, 15))
id range
1 0-499
3 500-999
2 1000-1199
select * from #temp1 order by cast (substring(range,0,charindex('-',range)) as int)
id range
1 0-499
3 500-999
2 1000-1199
I have column Amount with 10,000 records and its look like this.
1.24E4
27.27E1
3.25E2
and etc.
Now I need to update the column to make this result
12400
272.7
325
I need to know how to convert and update the column from varchar to decimal.
Take note that my Column Amount is in Varchar Data type.
select convert(float, '1.24E4')
select convert(float, '27.27E1')
select convert(float, '3.25E2')
Simply update with a cast to FLOAT:
UPDATE YOUR_TABLE
SET YOUR_COLUMN = CAST(YOUR_COLUMN AS FLOAT)
WHERE....your condition if there
I'm working on a query with a varchar column called ALCOHOL_OZ_PER_WK. Part of the query includes:
where e.ALCOHOL_OZ_PER_WK >= 14
and get the errors:
Arithmetic overflow error converting varchar to data type numeric.
and:
Error converting data type varchar to numeric.
Looking into the values actually stored in the column, the largest look close to 100, but some of the entries are ranges:
9 - 12
1.5 - 2.5
I'd like to get the upper limit (or maybe the midpoint of the range) from rows with entries like this and have it be the value being compared to 14.
What would be the (or an) easy way to do this?
As always, thank you!
Your DB is obviously result of some survey, and it seems to contain the original survey data. The usual way is to run this through an ECCD (Extract, Clean, Conform, Deliver) process and store clean and standardized data into a separate database (maybe a warehouse) which can then be used for analytics and reporting.
If you have SSIS use data profiling task to get an idea of types of strings you have in there. The Column Pattern Profile reports a set of regular expressions on the string column, so you will get an idea of what's inside those strings. If you do not have SSIS, you can use eobjects DataCleaner to do the same.
If you can not spare a new database or at least a new table -- at minimum add a numeric column to this table and then extract numeric values form those strings into the new column. You may want to use "something else" (SSIS, Pentaho Kettle, Python, VB, C#) to do this -- in general T-SQL in not very good at string processing.
My guess is that this is not the only column that has garbage inside, so any analysis that you may run on this may be worthless.
And if you still think that the ranges are the only problem, this example may help:
First some data
DECLARE #myTable TABLE (
AlUnits varchar(10)
) ;
INSERT INTO #myTable
(AlUnits )
VALUES ( '10' )
, ( '15' )
, ( '20' )
, ( '7 - 12' )
, ( '3 - 5' )
;
The query splits records into two groups, numeric and not numeric -- assumed ranges.
;
WITH is_num
AS ( SELECT CAST(AlUnits AS decimal(6, 2)) AS Units_LO
,CAST(AlUnits AS decimal(6, 2)) AS Units_HI
FROM #myTable
WHERE ISNUMERIC(AlUnits) = 1
),
is_not_num
AS ( SELECT CAST( RTRIM(LTRIM(LEFT(AlUnits,
CHARINDEX('-', AlUnits) - 1)))
AS decimal(6,2)) AS Units_LO
,CAST(RTRIM(LTRIM(RIGHT(AlUnits,
LEN(AlUnits)
- CHARINDEX('-', AlUnits))))
AS decimal(6,2)) AS Units_HI
FROM #myTable
WHERE ISNUMERIC(AlUnits) = 0
)
SELECT Units_LO
,Units_HI
,CAST(( Units_LO + Units_HI ) / 2.0 AS decimal(6, 2)) AS Units_Avg
FROM is_num
UNION ALL
SELECT Units_LO
,Units_HI
,CAST(( Units_LO + Units_HI ) / 2.0 AS decimal(6, 2)) AS Units_Avg
FROM is_not_num ;
Returns:
Units_LO Units_HI Units_Avg
----------- ----------- ----------
10.00 10.00 10.00
15.00 15.00 15.00
20.00 20.00 20.00
7.00 12.00 9.50
3.00 5.00 4.00
Not sure about easy ways.
A proper way is to store the numbers in two columns, ALCOHOL_OZ_PER_WK_MIN and ALCOHOL_OZ_PER_WK_MAX.
As you say you need to calculate numeric values, which you can then use in your query.
Probably the easiest way is to use some simple logic to calculate the average or upper limit using string functions, and string to numeric functions.
If all you want is the upper limit, just get the characters after the '-' and use that.
"probably because some are ranges" - do you get that "range" is not a SQL Server Data type? You've got non-numeric data you're trying to convert into numeric data, and you've got a scalar value you're comparing to a non-scalar value.
This database has some issues.