Have a fiscal quarter column, and I want to add a column that displays the previous quarter in the same row. I've done this successfully in tableau with logic like below.
IF RIGHT([current_qtr], 1) = "1"
THEN LEFT([current_qtr],2)+ STR(INT(MID([current_qtr], 3,2)) -1) +"Q4"
ELSE LEFT([current_qtr],5)+ STR(INT(RIGHT([current_qtr],1)) -1)
END
Example of expected output in snowflake
current_qtr
previous_qtr
other columns
FY21Q1
FY20Q4
etc
FY21Q2
FY21Q1
etc
When I try to do this in snowflake though I keep getting this "Numeric value '' is not recognized error instead. Any ideas how to fix? Below is what I attempted.
SELECT *,
CASE
WHEN SUBSTR(p.current_qtr,5,1) = 1
THEN SUBSTR(p.current_qtr,1,2) || TRY_CAST(SUBSTR(p.current_qtr,3,2) as INTEGER)-1 || 'Q4'
ELSE SUBSTR(p.current_qtr,5,1) || TRY_CAST(SUBSTR(p.current_qtr,3,2) as INTEGER)-1
End As prev_qtr
FROM table as p
This logic might look way better as a SQL UDF than as a big pile of strange SQL inside a query:
create or replace function prev_quarter_formatted(x string)
returns string
as
$$
(
select 'FY' || to_varchar(prev_q, '%y') || 'Q' || quarter(prev_q)
from (
select substr(x, 3,2) year
, (1+3*(substr(x, 6,1)::int-1)) q_to_month
, to_date(year||'-'||q_to_month||'-01', 'yy-mm-dd') as_date
, dateadd(month, -3, as_date) prev_q
)
)
$$
;
select prev_quarter_formatted('FY21Q1') a
;
Notice that for the logic I transformed the quarter into a date, subtracted 3 months, and formatted again.
There are some subtle differences in the syntax for casting. You can use your current CASE statement with some minor adjustments:
SELECT *,
CASE
WHEN SUBSTR(p.current_qtr,6,1) = '1'
THEN SUBSTR(p.current_qtr,1,2) || ((SUBSTR(p.current_qtr,3,2))::int - 1) || 'Q4'
ELSE SUBSTR(p.current_qtr,1,2) || SUBSTR(p.current_qtr,3,2) || (SUBSTR(p.current_qtr,3,2)::int-1)
END AS prev_qtr
FROM table1 as p
Related
I have a column of financial data that shows. Some figures are positive and some are negative.
Is it possible to change a number like -945 to (945) this is on SQL Server 2005.
The following expression should work for most cases:
SELECT num, CASE
WHEN num < 0 THEN '(' + CAST(-num AS VARCHAR(11)) + ')'
ELSE CAST(num AS VARCHAR(11))
END AS frmtd
FROM (
SELECT 0 AS num UNION ALL
SELECT 945 UNION ALL
SELECT -945
) tests
There is an SQL function called ABS() that basically changes negative and positive numbers to just their relative value from 0, meaning it removes the minus but doesn't affect positive values.
You can find out more about it here
You can also try using Replace function in Sql Server as shown below.
When value is in (-) ve.
Select CAST(REPLACE(CAST(-945 as Varchar(4)), '-', '') as Int)
When value is already in (+) ve.
Select CAST(REPLACE(CAST(945 as Varchar(4)), '-', '') as Int)
The output in both case will be: 945
I have a column in SQL server and I want to add 7 for the words which begin by a and add 8 for the words which begin by t.
Here is my column:
add-on
above
tv
their
french
And I want this:
7add-on
7above
8tv
8their
french
I am looking for a query which could do that.
Thank you very much!
You can use left() & do the concatenation :
select t.*,
(case left(col, 1)
when 'a' then concat(7, col)
when 't' then concat(8, col)
else col
end)
from table t;
Use a case expression with substring to get the results you require.
select concat(
(case when substring(col,1,1)='a' then '7'
when substring(col,1,1)='t' then '8'
end
)
,col
) as modified_col
from table
You need 2 update queries. Try like:
UPDATE myTable SET myColumn='7'+myColumn WHERE myColumn LIKE 'a%';
UPDATE myTable SET myColumn='8'+myColumn WHERE myColumn LIKE 't%'
Use CASE statement to check the first char, returned by SUBSTRING function, and calculate a prefix to add to your data:
select
case substring(column, 1, 1)
when 'a' then '7'
when 't' then '8' else '' end + column as NewColumn
from table
In sql server 2008 :
select
case when substring(column,1,1)='a' then ( '7 ' + column)
case when substring(column,1,1)='t' then ( '8 ' + column)
else column end as column from table
In sql server 2012 or above :
select
case when substring(column,1,1)='a' then concat( '7 ',column)
case when substring(column,1,1)='t' then concat( '8 ',column)
else column end as column from table
I have two columns: p.firstName and p.lastName.
Now I want to display the length of both names combined, the problem is, that in some fields of p.lastName the value "null" is stored.
When I try to do it like this:
LENGTH(p.firstName + p.lastName)
I get an error:
ORA-01722 invalid number
However, if I split it up
LENGTH(p.firstName) + LENGTH(p.lastName)
it doesn't give me an error message. But the length of the sum is NULL, even if the firstName does have a few characters. The NULL of p.LastName breaks it so to say.
Anyone has an idea?
You can Use IFNULL(), ISNULL(), COALESCE(), and NVL() Functions
SELECT LENGTH(COALESCE(p.firstName,'') + COALESCE(p.lastName,'')) AS Len FROM TableName
OR
SELECT LENGTH(ISNULL(p.firstName,'') + ISNULL(p.lastName,'')) AS Len FROM TableName
OR
SELECT LENGTH(IFNULL(p.firstName,'') + IFNULL(p.lastName,'')) AS Len FROM TableName
OR
SELECT LENGTH(NVL(p.firstName,'') + NVL(p.lastName,'')) AS Len FROM TableName
OR
SELECT LENGTH(p.firstName || p.lastName) AS Len FROM TableName
You may to concat columns instead using || operator:
LENGTH(p.firstName || p.lastName)
Example:
select ('abc'||null||'d') from dual; -- abcd
select length('abc'||null||'d') from dual; -- 4
Try this
select case when p.firstname is null then 0 else length(p.firstName) end +
case when p.lastName is null then 0 else
length(nickname) end from p
Oracle usually treats an empty string as NULL:
COALESCE(LENGTH(p.firstName), 0) + COALESCE(LENGTH(p.lastName),0)
I think it is much better to use it this way...
SELECT LENGTH(ISNULL(p.firstName,'') + ISNULL(p.lastName,'')) AS length FROM TableName
NOTE: Oracle behaves differently in the dealing of blank characters:
---------Oracle
SELECT LENGTH('') , LENGTH(null) FROM DUAL
--result: null,null
---------Postgress
SELECT LENGTH('') , LENGTH(null)
--result: 0,null
---------SQL Server
SELECT LEN('') , LEN(null)
--result: 0,null
---------MySQL
SELECT LENGTH('') , LENGTH(null)
--result: 0,null
I am in some Confusion to find which of these will improve the query execution time.
Data base and Table information:
I am using database which is hosted in remote location might be US.
Table is having approx 2 cr. records and having only 2 columns String format.
I wants to extract the data from that table using filters and some modification.
in select statements.
DB_KEY is having unique key indexing
Select statement condition:
CASE WHEN (INSTR(DB_KEY , 'MsgOutMdlName' ) > 0) THEN
reverse(SUBSTR( reverse(DB_KEY) , INSTR (reverse(DB_KEY) , '|' , 1 ) ,LENGTH(DB_KEY) )) || 'MsgOutMdlName' ELSE
reverse(SUBSTR( reverse(DB_KEY) , INSTR (reverse(DB_KEY) , '|' , 1 ) ,LENGTH(DB_KEY) )) || 'MsgInAttName'
Or
CASE WHEN INSTR(DB_KEY , 'MsgOutMdlName' ) > 0 THEN
SUBSTR( DB_KEY , 0, INSTR(DB_KEY , '|' , 1, REGEXP_COUNT (DB_KEY, '[^|]+')-1 ) ) || 'MsgOutMdlName' ELSE
SUBSTR( DB_KEY , 0, INSTR(DB_KEY , '|' , 1, REGEXP_COUNT (DB_KEY, '[^|]+')-1 ) ) || 'MsgInAttName' end
Or
CASE WHEN DB_KEY like '%MsgOutMdlName'
then any one of above code:
and in where clause:
WHERE 1 = ( case when DB_VALUE is not null and
(DB_KEY LIKE 'TP|%MsgInAttName' or DB_KEY LIKE 'TP|%MsgOutMdlName') then 1 else null end )
Or use like operator in where clause.
Please suggest me the best approach.
DB_key are having dynamic data values.
I have already use function based indexing but didn't get better performance.
this refers to a question asked by someone else previously
previous question
my question is how do I adapt this solution so that before any function/script is ran the name and value fields are stripped of any additional + and updated so no additional + remain.
For e.g.
Name Value
A+B+C+ 1+2+3+
A++B 1++2
this should be updated to
Name Value
A+B+C 1+2+3
A+B 1+2
once this update has taken place, I can run the solution provided in the previous question.
Thanks
You need to replace ++ with + and to remove the + at the end of the string.
/* sample data */
with input(Name, Value) as (
select 'A+B+C+' ,'1+2+3+' from dual union all
select 'A++B' ,'1++2' from dual
)
/* query */
select trim('+' from regexp_replace(name, '\+{2,}', '+') ) as name,
trim('+' from regexp_replace(value, '\+{2,}', '+') ) as value
from input
If you need to update a table, you may need:
update yourTable
set name = trim('+' from regexp_replace(name, '\+{2,}', '+') ),
value= trim('+' from regexp_replace(value, '\+{2,}', '+') )
In a more compact way, without the external trim ( assuming you have no leading +):
/* sample data */
with input(Name, Value) as (
select 'A+B+C+' ,'1+2+3+' from dual union all
select 'A++B+++C+' ,'1++2+++3+' from dual union all
select 'A+B' ,'1+2' from dual
)
/* query */
select regexp_replace(name, '(\+)+(\+|$)', '\2') as name,
regexp_replace(value, '(\+)+(\+|$)', '\2') as value
from input
You could use something on the lines of:
Select substr('1+2+3+', 0, length('1+2+3+')-1) from dual ;
Select replace('1++2', '++', '+') from dual;
I'm assuming you have the output already present in a variable you can play with.
EDIT:
Here's a function that can solve the problem (You can call this function in your select clauses thereby solving the problem):
CREATE OR REPLACE Function ReplaceChars
( name_in IN varchar2 )
RETURN varchar2
IS
changed_string varchar2(20) ;
BEGIN
changed_string:=replace(name_in, '++', '+') ;
CASE WHEN substr(changed_string, -1) in ('+')
then
changed_string:=substr(changed_string,0, length(changed_string) - 1) ;
else changed_string:=changed_string ;
end CASE ;
RETURN changed_string;
END;
You can use the below:
LTRIM(RTRIM (REGEXP_REPLACE (column_name, '\+{2,}', '+'), '+'),'+')
Eg:
SELECT LTRIM(RTRIM (REGEXP_REPLACE ('+A+++B+C+++D++', '\+{2,}', '+'), '+'),'+') VALUE
FROM DUAL;
returns output: A+B+C+D
if youre working with ssms, GIVE IT A GO:::
UPDATE tablename
SET colname=
CASE colname WHEN LIKE '%++%' THEN
WHILE colname LIKE '%++%'
(REPLACE(colname,++,+))
END LOOP
WHEN LIKE '%+' THEN
SUBSTR(colname, 1, LENGTH(colname)-1)
WHEN LIKE '+%' THEN
SUBSTR(colname, 2, LENGTH(colname))
ELSE
colname
END