I select the price 1000000 and I need to format it to $1,000,000. How can I do that in SQL?
To format with commas, you can use CONVERT with a style of 1:
declare #money money = 1000000
select '$' + convert(varchar, #money, 1)
will produce $1,000,000.00
If you want to remove the last 3 characters:
select '$' + left(convert(varchar, #money, 1), charindex('.', convert(varchar, #money, 1)) - 1)
and if you want to round rather than truncate:
select '$' + left(convert(varchar, #money + $0.50, 1), charindex('.', convert(varchar, #money, 1)) - 1)
Creating Function:
CREATE FUNCTION [dbo].[f_FormatMoneyValue]
(
#MoneyValue money
)
RETURNS VARCHAR(50)
AS
BEGIN
RETURN cast(#MoneyValue as numeric(36,2))
END
Using in Select Query:
Select dbo.f_FormatMoneyValue(isnull(SalesPrice,0))SalesPrice from SalesOrder
Output:
100.00
Formatting Money Value with '$' sign:
CREATE FUNCTION [dbo].[f_FormatMoneyWithDollar]
(
#MoneyValue money
)
RETURNS VARCHAR(50)
AS
BEGIN
RETURN '$' + convert(varchar, #MoneyValue, 1)
END
Output:
$100.00
Note: The above sample is for the money field. You can modify this function according to your needs
Hope this helps you..! :D
SELECT FORMAT(price, 'C2', 'en-us')
The SQL Server money datatype is just decimal(10, 4). To my knowledge there is no datatype that will present the way you want.
Adding the dollar sign and commas is something that should belong in the application logic, but if you really must do it through a database object consider adding the dollar sign, and commas every three characters (after the decimal point). In other words, you'll have to convert the int to varchar and do string manipulation.
It depends, however, there's no simple way to do it in standard SQL specs(SQL-92, SQL-2003, etc.).
For PostgreSQL PL/pgSQL and Oracle PL/SQL, you can use to_char to format numbers:
select to_char(1234567.123, 'FM$999,999,999.99')
Which gives output:
$1,234,567.12
See: http://www.postgresql.org/docs/7/static/functions2976.htm
Related
I have store weight in lbs in my column which I need to convert to KG. I was able to do it with a simple query:
SELECT ( weight * 0.45 ) as weight from TABLE
However, this doesn't work values which are stored as a range, ex. '200 - 300'. If I use the same query it returns 440.925 instead of 440-661. I understand this is happening because I'm multiplying string but is there a way I can multiple a range value (200-300) to get the desired result.
If not, how should I convert this range ideally?
SUBSTRING_INDEX is useful here:
SELECT IF(
INSTR(weight, '-') > 0, /* Does weight contain a dash? */
CONCAT( /* Yes? Multiply each, and return them: */
SUBSTRING_INDEX(weight, '-', 1) * 0.45,
' - ',
SUBSTRING_INDEX(weight, '-', -1) * 0.45
),
weight * 0.45 /* No? Just simply multiply the weight */
) AS `range`
FROM test
First, we check to see if weight contains a dash, and if it does, split it up, and multiply them out individually.
See an example here: https://www.db-fiddle.com/f/iELvWDjpVGBZEkpdR4jtsK/0
If i understand your question correctly you need to do something like below.
SELECT
CONCAT (
SUBSTRING_INDEX(SUBSTRING_INDEX(column, ' - ', 1), ' - ', -1) * 0.45
, ' - '
, SUBSTRING_INDEX(SUBSTRING_INDEX(column, ' - ', 2), ' - ', -1) * 0.45
)
FROM
table
1) Nesting SUBSTRING_INDEX functions makes it possible to extract items from a string.
2) CAST function is not needed because of MySQL autotype cast.
Using CAST, and SUBSTRING_INDEX functions.
CAST will ensure that even if there are more spaces on either side of the '-' (hyphen) character, it will still convert it into a valid number. You can change the DECIMAL(10,4) to any precision, as per your application requirements.
SUBSTRING_INDEX will find the substring before the occurence of '-' (hyphen) character.
Try this:
SELECT
CONCAT(CAST(SUBSTRING_INDEX(weight, '-', 1) AS DECIMAL(10,4)) * 0.45,
'-',
CAST(SUBSTRING_INDEX(weight, '-', -1) AS DECIMAL(10,4)) * 0.45)
AS weight
FROM table
I have a requirement where I need to mask all but characters in position 1,4,8,12,16.. for a variable length string with 'X'
For example:
Input string - 'John Doe'
Output String - 'JXXn xxE'
SPACE between the two strings must be retained.
Kindly help or reach out for more details if required.
I think maybe an external function would be best here, but if that's too much to bite off, you can get crafty with strtok_split_to_table, xml_agg and regexp_replace to rip the string apart, replace out characters using your criteria, and stitch it back together:
WITH cte AS (SELECT REGEXP_REPLACE('this is a test of this functionality', '(.)', '\1,') AS fullname FROM Sys_Calendar.calendar WHERE calendar_date = CURRENT_DATE)
SELECT
REGEXP_REPLACE(REGEXP_REPLACE((XMLAGG(tokenout ORDER BY tokennum) (VARCHAR(200))), '(.) (.)', '\1\2') , '(.) (.)', '\1\2')
FROM
(
SELECT
tokennum,
outkey,
CASE WHEN tokennum = 1 OR tokennum mod 4 = 0 OR token = ' ' THEN token ELSE 'X' END AS tokenout
FROM TABLE (strtok_split_to_table(cte.fullname, cte.fullname, ',')
RETURNS (outkey VARCHAR(200), tokennum integer, token VARCHAR(200) CHARACTER SET UNICODE)) AS d
) stringshred
GROUP BY outkey
This won't be fast on a large data set, but it might suffice depending on how much data you have to process.
Breaking this down:
WITH cte AS (SELECT REGEXP_REPLACE('this is a test of this functionality', '(.)', '\1,') AS fullname FROM Sys_Calendar.calendar WHERE calendar_date = CURRENT_DATE)
This CTE is just adding a comma between every character of our incoming string using that regexp_replace function. Your name will come out like J,o,h,n, ,D,o,e. You can ignore the sys_calendar part, I just put that in so it would spit out exactly 1 record for testing.
SELECT
tokennum,
outkey,
CASE WHEN tokennum = 1 OR tokennum mod 4 = 0 OR token = ' ' THEN token ELSE 'X' END AS tokenout
FROM TABLE (strtok_split_to_table(cte.fullname, cte.fullname, ',')
RETURNS (outkey VARCHAR(200), tokennum integer, token VARCHAR(200) CHARACTER SET UNICODE)) AS d
This subquery is the important bit. Here we create a record for every character in your incoming name. strtok_split_to_table is doing the work here splitting that incoming name by comma (which we added in the CTE)
The Case statement just runs your criteria swapping out 'X' in the correct positions (record 1, or a multiple of 4, and not a space).
SELECT
REGEXP_REPLACE(REGEXP_REPLACE((XMLAGG(tokenout ORDER BY tokennum) (VARCHAR(200))), '(.) (.)', '\1\2') , '(.) (.)', '\1\2')
Finally we use XMLAGG to combine the many records back into one string in a single record. Because XMLAGG adds a space in between each character we have to hit it a couple of times with regexp_replace to flip those spaces back to nothing.
So... it's ugly, but it does the job.
The code above spits out:
tXXs XX X XeXX oX XhXX fXXXtXXXaXXXy
I couldn't think of a solution, but then #JNevill inspired me with his idea to add a comma to each character :-)
SELECT
RegExp_Replace(
RegExp_Replace(
RegExp_Replace(inputString, '(.)(.)?(.)?(.)?', '(\1(\2[\3(\4', 2)
,'(\([^ ])', 'X')
,'(\(|\[)')
,'this is a test of this functionality' AS inputString
tXXs XX X XeXX oX XhXX fXXXtXXXaXXXy
The 1st RegExp_Replace starts at the 2nd character (keep the 1st character as-is) and processes groups of (up to) 4 characters adding either a ( (characters #1,#2,#4, to be replaced by X unless it's a space) or [ (character #3, no replacement), which results in :
t(h(i[s( (i(s[ (a( (t[e(s(t( [o(f( (t[h(i(s( [f(u(n(c[t(i(o(n[a(l(i(t[y(
Of course this assumes that both characters don't exists in your input data, otherwise you have to choose different ones.
The 2nd RegExp_Replace replaces the ( and the following character with X unless it's a space, which results in:
tXX[s( XX[ X( X[eXX( [oX( X[hXX( [fXXX[tXXX[aXXX[y(
Now there are some (& [ left which are removed by the 3rd RegExp_Replace.
As I still consider me as a beginner in Regular Expressions, there will be better solutions :-)
Edit:
In older Teradata versions not all parameters were optional, then you might have to add values for those:
RegExp_Replace(
RegExp_Replace(
RegExp_Replace(inputString, '(.)(.)?(.)?(.)?', '(\1(\2[\3(\4', 2, 0 'c')
,'(\([^ ])', 'X', 1, 0 'c')
,'(\(|\[)', '', 1, 0 'c')
I have a database which has a field titled 'address1'. If there is only 1 string in this field for a record, I am able to correct the case from eg 'PAULSTOWN' to 'Paulstown', or 'bishopslough' to 'Bishopslough'.
I have done this by creating a function:
CREATE FUNCTION init_cap (s VARCHAR(255))
RETURNS VARCHAR(255) DETERMINISTIC
RETURN CONCAT( UPPER( SUBSTRING( s, 1, 1 ) ) , LOWER( SUBSTRING( s FROM 2 ) ) );
Then using:
UPDATE customer SET address1 = init_cap(address1);
To correct records.
However, this does not fully correct records that contain more than one string, eg 'dalesfort road' will only be corrected to 'Dalesfort road' and not 'Dalesfort Road'. There are also some entries with more than 2 strings.
How could I change the above function to cater for 2 or more strings? Also is that function declared correctly, or should I be using begin and end sections?
It's ok I found the answer at artfulsoftware.com
Now I just need to analyse the code and learn how it works!
I have a column in one of my tables, which is TIME format (00:00:00). I am trying to sum the entire column and display it as same (00:00:00).
I have tried using the following but it is not giving me anywhere near the correct answer.It's giving me 22.12:44:00 and manual calcaulation tells me it should be close to 212:something:something
SELECT SEC_TO_TIME( SUM( TIME_TO_SEC( vluchttijd ) ) ) AS totaltime FROM tbl_vluchtgegevens
Any recommendations?
You can try like this:-
SELECT SEC_TO_TIME(SUM(SECOND(vluchttijd ))) AS totaltime FROM tbl_vluchtgegevens;
or try this(althoug this is not a good approach):
SELECT concat(floor(SUM( TIME_TO_SEC( `vluchttijd ` ))/3600),":",floor(SUM( TIME_TO_SEC( `vluchttijd ` ))/60)%60,":",SUM( TIME_TO_SEC( `vluchttijd ` ))%60) AS total_time
FROM tbl_vluchtgegevens;
Edit:-
Try this:-
select cast(sum(datediff(second,0,dt))/3600 as varchar(12)) + ':' +
right('0' + cast(sum(datediff(second,0,dt))/60%60 as varchar(2)),2) +
':' + right('0' + cast(sum(datediff(second,0,dt))%60 as varchar(2)),2)
from TestTable
Working SQL Fidlle
In MySQL, the TIME type is rather limited in range. Moreover many time function do not accept values greater that 23:59:59, making it really usable only to represent the time of the day.
Given your needs, your best bet is probably to write a custom function that will mimic SEC_TO_TIME but allowing much greater range:
CREATE FUNCTION SEC_TO_BIGTIME(sec INT)
RETURNS CHAR(10) DETERMINISTIC
BEGIN
SET #h = sec DIV 3600;
SET #m = sec DIV 60 MOD 60;
SET #s = sec MOD 60;
RETURN CONCAT(
LPAD(#h, 4, '0'),
':',
LPAD(#m, 2, '0'),
':',
LPAD(#s, 2, '0')
);
END;
And here is how to use it:
create table tbl (dt time);
insert tbl values
('09:00:00'), ('01:00:00'), ('07:50:15'), ('12:00:00'),
('08:30:00'), ('00:45:00'), ('12:10:30');
select SEC_TO_BIGTIME(sum(time_to_sec(dt))) from tbl;
Producing:
+--------------------------------------+
| SEC_TO_BIGTIME(SUM(TIME_TO_SEC(DT))) |
+--------------------------------------+
| 0051:15:45 |
+--------------------------------------+
See http://sqlfiddle.com/#!8/aaab8/1
Please note the result is a CHAR(10) in order to overcome TIMEtype limitations. Depending how you plan to use that result, that means that you may have to convert from that string to the appropriate type in your host language.
This worked for me:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(vluchttijd))) AS totaltime FROM tbl_vluchtgegevens;
I have a query block for retrieving data from MSSQL Server. the query has some hardcoded date values which needs to be changed everyday to import the daily feed. I need to automate this execution. I am using cloverETL for executing the query right now.
Here is the query (its a query to retrieve sharepoint activity data)
use
DocAve_AuditDB;
DECLARE
#ParameterValue VARCHAR(100),
#SQL
VARCHAR(MAX)
SET
#SQL = STUFF((SELECT 'UNION ALL SELECT COL_ItemTypeName, COL_UserName, COL_MachineIp, COL_DocLocation, DATEADD(SECOND, COL_Occurred / 1000, ''19700101 00:00'') as Date_Occurred, COL_EventAction FROM '+ TABLE_NAME + ' WHERE DATEADD(SECOND, COL_Occurred / 1000, ''19700101 00:00'') BETWEEN '+ '''20120515'''+ 'AND' + '''20120516'''+ 'AND ' + 'COL_ItemTypeName='+ '''Document''' AS 'data()'
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME LIKE '%2012_05%'
FOR
XML PATH('')),1,10,'')
EXEC
(#SQL)
In the above block I want the TABLE_NAME LIKE param i.e. %2012_05% to be a variable retrieved from the current data and also the date values in the between clause
BETWEEN '+ '''20120515'''+ 'AND' + '''20120516'''
to be todays date-1 and todays date
should create a small java program for handling this or it can be done directly in the query itself? if yes how?
Thanks in Advance
Use GETDATE() or CURRENT_TIMESTAMP to obtain the current date (and time).
Use CONVERT() with the 112 format specifier to convert the current timestamp to a string formatted as YYYYMMDD.
Use DATEADD() for calculations (like subtracting one day) on dates/times.
Use SUBSTRING() to subtract parts from the formatted date string to rearrange them to the %YYYY_MM% format.
Or you can use inline ctl notation in DBInputTable:
SELECT 'UNION ALL SELECT COL_ItemTypeName, COL_UserName, COL_MachineIp, COL_DocLocation, DATEADD(SECOND, COL_Occurred / 1000, ''19700101 00:00'') as Date_Occurred, COL_EventAction FROM `date2str(today(), "yyyy_MM")` WHERE DATEADD(SECOND, COL_Occurred / 1000, ''19700101 00:00'') BETWEEN '+ '''`date2str(today(), "yyyyMMdd")`'''+ 'AND' + '''`date2str(dateAdd(today(),1,day), "yyyyMMdd")`'''+ 'AND ' + 'COL_ItemTypeName='+ '''Document''' AS 'data()'