I want to return a list of results with the following WHERE clause:
SELECT ...
FROM XTABLE
WHERE MMONTH = to_char(to_date('03/2013','mm/yyyy'),'mm')
AND MYEAR = to_char(to_date('03/2013','mm/yyyy'),'yyyy')
where MMONTH is a column of type CHAR(3 Bytes) and MYEAR is a column of type CHAR(4 Bytes).
Why doesn't it work compared to
SELECT ...
FROM XTABLE
WHERE TO_DATE(MMONTH,'MM') = to_date(to_char(to_date('03/2012','mm/yyyy'),'mm'),'mm')
AND TO_DATE(MYEAR,'yyyy') = to_date(to_char(to_date('03/2012','mm/yyyy'),'yyyy'),'yyyy')
I am reluctant to change the format of the date ('03/2012') on the right as I have additional queries that use the same date, so I thought using just one type of date would be good.
From the Oracle documentation,
The CHAR data type specifies a fixed-length character string. Oracle ensures that all values stored in a CHAR column have the length specified by size. If you insert a value that is shorter than the column length, then Oracle blank-pads the value to column length.
So, if you insert '03' into MMONTH column, it will have a space at the end. The output of to_char function will return simply '03' without any space. Hence, when you compare it won't match.
Recommended way, is to change the datatype of your columns to VARCHAR2. You can also change the column size of MMONTH to 2.
Following on from Ramblin' Man's explanation of the problem, if you really can't change the data type, you could use where trim(mmonth) = which has index implications, or apply rpad or or cast to your to_char. SQL Fiddle of all three options, but personally I'd go for the cast as that's most self-explanatory:
SELECT ...
FROM XTABLE
WHERE MMONTH = cast(to_char(to_date('03/2013','mm/yyyy'),'mm') as char(3))
AND MYEAR = to_char(to_date('03/2013','mm/yyyy'),'yyyy');
Related
I have a DB2 table where NUM column is defined as INTEGER in DB2 and the query result is shown below,
NUM columns have numeric values which needs to be converted to date format. This numeric values are nothing but duration from 01.01.1850. Example : 01.01.1850 + 57677 days = 01.12.2007.
So Is it possible to convert or cast the numeric value into date fields in DB2 , so that the select query from the table can result as shown below after converting a numeric field into date field,
You may use the scalar ADD_DAYS function:
SELECT EMP_ID, ADD_DAYS('1850-01-01', NUM) AS NUM
FROM yourTable;
Not all Db2 products & versions have the ADD_DAYS function.
The following expression works for all of them.
You may optionally add DAY or DAYS at the end.
DATE ('1850-01-01') + 57677
select to_number(replace(nvl('-100,000',0),'',','),'999,999,999.99')from dual;
... produces the output: 100000
Now I use the same expression in my procedure with table column:
select to_number(replace(nvl(TABLEA.VOLUME,0),'',','),'999,999,999.99')from TABLEA;
... and get the output: INVALID NUMBER
Column VOLUME in TABLEA is of type VARCHAR2.
Most certainly the contents of column VOLUME are stored as strings without the grouping character ( , ). Thus the strings violate the format in the conversion with to_number.
In addition, the argument order in REPLACE makes no sense.
Finally, you want to swap the calls to NVL and REPLACE.
So - assuming that you want to parse numbers with 2 fractional digits given as strings - use the following:
select to_number ( nvl ( replace (TABLEA.VOLUME, ',', ''), 0), '999999999.99') from TABLEA;
Seems you want to convert the string values to money format.
First, consider replace as you did by switching '' and ',' parameters in the argument order to remove the commas, and making suitable for numeric conversion as :
to_number(replace(nvl(str,0),',','')),
and then apply the money format as :
with tableA as
(
select '-100,000' as volume
from dual
)
select to_char(
to_number(replace(nvl(volume,0),',',''))
,'fm999G999G990D00','NLS_NUMERIC_CHARACTERS = ''.,''')
as Money
from tableA;
MONEY
-----------
-100,000.00
Depending on the currency displaying style the order of dot and comma can be switched as
'NLS_NUMERIC_CHARACTERS = '',.''' to display the money as -100.000,00.
P.S. first of all, you need to make sure all the data for volume column can be casted to number to be able to use to_number() conversion.
Demo
When casting from a varchar data type to a date datatype, my query results are altering the day of the original field. For example, the below two queries
select to_Date('2017-12-15 00:11:10.167664+00', 'YYYY-MM-DD')
select '2017-12-15 00:11:10.167664+00'::date
return a value of "2017-12-14". I am querying a vertica database using DataGrip.
You can just take the leftmost 10 characters of the string and then convert to date, e.g.:
SELECT TO_DATE(LEFT('2017-12-15 00:11:10.167664+00',10), 'YYYY-MM-DD')
I have a db where I have converted 2 date columns to varchar for the purpose of getting 1 column substringed into another. However, now I don't seem to be able to convert the datatype when I try to use:
ALTER TABLE datacomplete
ALTER COLUMN yearmonth TYPE DATE; /*Can't find a way to specify a format*/
It throws this error:
ERROR: column "yearmonth" cannot be cast automatically to type date
Hint: You might need to specify "USING yearmonth::date".
I'm not sure how to use that command at all, could anyone potentially assist?
My first column is in the format of yyyy-mm-dd, however I'd like it to be yyyymm only, but I'm guessing this is easier once I convert the datatype to date and I can somehow switch formats.
The second column only shows the year so I need to convert it to date as format 'yyyy'.
UPDATE: The first one was solved, now I need to convert the second to 'yyyy'
ALTER TABLE pscomplete_1 ALTER COLUMN "year" TYPE DATE USING "year"::date;
It throws this error
15:12:51 [ALTER - 0 rows, 1.062 secs] [Code: 0, SQL State: 22007] ERROR: >invalid input syntax for type date: "2016"
... 1 statement(s) executed, 0 rows affected, exec/fetch time: 1.062/0.000 sec >[0 successful, 1 errors]
The USING keyword allows you to give the translation function to PostgreSQL.
For your first column it is easy for you already have a correct DATE format:
ALTER TABLE datacomplete ALTER COLUMN yearmonth TYPE DATE USING yearmonth::DATE;
For your second column it is unclear for PostgreSQL which exact date you want. Let's say we want the first of January of the given year:
ALTER TABLE datacomplete ALTER COLUMN year TYPE DATE USING (year || '-01-01')::DATE;
I understood you were starting from a VARCHAR column in the format 'YYYY-MM-DD'.
So I'll do the same.
And you want a column in the date format, and you want a yearmonth in all-digits format.
If I'm not forced to use leading zeroes in an all-digits column, I prefer INT to string columns.
And I prefer to make the same derivation only once if I can do that.
This is why I use a WITH clause (global table expression) to cast the varchar to date, and then I use the resulting date for the DATE_PART() function I use to create the yearmonth column. I have seen very often that date arithmetics are safer and often faster than subtring-ing the date literal (remember, the Americans format dates differently from the Europeans, there are different formats within Europe, and also in Asia, and not all like the ISO date format). So I derive yearmonth as the year multiplied by 100, plus the month, and as DATE_PART() returns a float, I cast the whole expression to INT.
So here goes:
WITH foo(varchar_dt) AS (
SELECT '2017-01-11'
UNION ALL SELECT '2016-12-11'
UNION ALL SELECT '2016-11-11'
UNION ALL SELECT '2016-10-11'
)
, foo_with_date AS (
SELECT
varchar_dt
, CAST(varchar_dt AS DATE) AS the_date
FROM foo
)
SELECT
varchar_dt
, the_date
, CAST(DATE_PART('year',the_date)*100 + DATE_PART('month',the_date) AS INT) AS yearmonth
FROM foo_with_date
;
varchar_dt|the_date |yearmonth
2017-01-11|2017-01-11| 201,701
2016-12-11|2016-12-11| 201,612
2016-11-11|2016-11-11| 201,611
2016-10-11|2016-10-11| 201,610
I can't help myself - I find this much cleaner, and filtering by yearmonth would become filtering by an integer, which is always at least a little bit faster than strings.
Happy playing
Marco the Sane
I have some varchar data that has numeric values in it, and I'm trying to strip out only the numeric part. I'm doing this as part of a stored proc that is doing a lot of other stuff at the same time, so I'm hoping to do this as part of an inline query.
My data values in this column look like this (added single ticks to show ends of varchars):
'1.25', '< 5 min', '2.35 minutes', '50.43 min'
What I want to get out of this column is:
1.25, 5, 2.35, 50.43
What my problem seems to be is how to determine the length of the numeric values in the single select, so I can lop off the characters at the end. Other than just choosing a value (my numbers are not always the same length), I'm not sure what I can do. My reason for wanting the numeric value only is because I need to convert it to a float for its destination value.
Here's what I've tried:
SUBSTRING(my_data, PATINDEX('%[0-9]%', my_data), 4)
It's a little complicated, but it works for your examples.
declare #val varchar(10)
select #val='50.43 min'
select
case
when PATINDEX('%[a-z]%',col) = 0
then col
else rtrim(SUBSTRING(col,1,PATINDEX('%[a-z]%',col)-1))
end
from
( select SUBSTRING(#val,PATINDEX('%[0-9]%',#val),PATINDEX('%[0-9]%',#val)
+len(#val)+1) as col ) t
Here you can find documentation about string functions.