REPLACE string with SUBSTRING function - sql-server

Given input data:
Col1
---------------------------------------
'-'::"varchar" COLLATE "default"
'-1'::integer
'0'::smallint
'1'::"varchar" COLLATE "default"
(get_val())::"timestamp"
0
0.0
10
210
90000
getdate()
I'm trying to replace the part of the string(column Col1) to empty string ''.
Want to replace anything after :: with empty string as shown below in the expected result.
Expected Result:
Col1 Col2
------------------------------------------------------------------------
'-'::"varchar" COLLATE "default" '-'
'-1'::integer '-1'
'0'::smallint '0'
'1'::"varchar" COLLATE "default" '1'
(get_val())::"timestamp" (get_val())
0 0
0.0 0.0
10 10
210 210
90000 90000
8 8
getdate() getdate()
My try:
SELECT Col1 REPLACE(REPLACE(Col1,SUBSTRING(Col1,CHARINDEX('::',Col1),LENGTH(Col1)),''),'(''','''')
FROM tbl_string_pattern;
But getting output like:
Col1 Col2
------------------------------------------------------------------------
'-'::"varchar" COLLATE "default" '-'
'-1'::integer '-1'
'0'::smallint '0'
'1'::"varchar" COLLATE "default" '1'
(get_val())::"timestamp" (get_val())
0 0
0.0 0
10 0
210 0
90000 0
8 8
getdate() )

Try this:
DECLARE #DataSource TABLE
(
[value] VARCHAR(128)
);
INSERT INTO #DataSource ([value])
VALUES ('''-''::"varchar" COLLATE "default"')
,('''-1''::integer')
,('''0''::smallint')
,('''1''::"varchar" COLLATE "default"')
,('(get_val())::"timestamp" ')
,('0')
,('0.0')
,('10 ')
,('210')
,('90000')
,('8')
,(null)
,('')
,('getdate()');
SELECT [value]
,REPLACE(REPLACE([value],SUBSTRING([value],CHARINDEX('::',[value]),LEN([value])),''),'(''','''')
,IIF(CHARINDEX('::', [value]) > 0, SUBSTRING([value], 0, CHARINDEX('::', [value])), [value])
-- John Cappellletti's idea
,left([value],charindex('::',[value]+'::')-1)
FROM #DataSource;

Related

Not able to convert data type varchar to numeric

i have below table :
id amount
12 974
11 929
9 837,5
4 606,5
and i have taken amount datatype as varchar(100). Now when i am trying to convert into decimal then at that time it giving me conversion error.
i have written the following query:
select id,cast(amount as decimal(10,2)) as amount from table order by amount desc
With the above query i am getting error : Error converting data type varchar to numeric.
How can i solve this issue?
create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
CREATE TABLE Table5
([id] int, [amount] varchar(100))
INSERT INTO Table5
([id], [amount])
VALUES
(12,'974'),
(11,'929'),
(9 ,'837,5'),
(4 ,'606,5')
select id,cast(token as decimal(10,2)) as amount from Table5
cross apply (select token from udf_splitstring([amount], ',') )a
id amount
12 974.00
11 929.00
9 837.00
9 5.00
4 606.00
4 5.00
or
2)
select id,amount,cast(replace (amount,',','.' )as decimal(10,2)) as amount1 from Table5
id amount amount1
12 974 974.00
11 929 929.00
9 837,5 837.50
4 606,5 606.50
3)
SELECT *,
TRY_PARSE( [amount] AS NUMERIC(10,2) USING 'El-GR' ) x
FROM Table5
If the string contain comma, you can not convert to decimal directly,
you can convert the string to Money type
;WITH t(id,amount)AS(
SELECT 12,'974' UNION
SELECT 11,'929' UNION
SELECT 9,'837,5.123' UNION
SELECT 4,'606,5'
)
SELECT id,CONVERT(MONEY,t.amount) FROM t WHERE ISNUMERIC(t.amount)=1
id
----------- ---------------------
4 6065.00
9 8375.123
11 929.00
12 974.00

move multiple columns to rows and one row as column

I have the result of my query in a temp table which looks something like shown below :
CREATE TABLE #temptable
(
productid INT,
date DATE,
Indicator varchar(max),
VendorCode INT,
morning INT,
noon INT,
evening INT
)
insert into #temptable values (101,'8-5-2016', 'High', 202, 0,1,0)
insert into #temptable values (101,'8-6-2016', 'High', 202, 0,0,1)
insert into #temptable values (101,'8-5-2016', 'Low', 202, 0,0,1)
insert into #temptable values (101,'8-6-2016', 'Low', 202, 0,0,1)
insert into #temptable values (101,'8-5-2016', 'Avg', 202, 1,0,1)
insert into #temptable values (101,'8-6-2016', 'Avg', 202, 0,0,1)
select * from #temptable
I need the output to look something like this :
I looked at using pivots but looks like that works only with aggregates ? Is there an easy way to do this ?
You can get the result you want by first applying the unpivot operator, and then pivot the result:
select
productid, VendorCode, date, time, Low, High, Avg
from (
select productid, VendorCode, date, time, Indicator, val
from #temptable
unpivot (val for time in ([morning],[noon],[evening])) u
) t
pivot (max(val) for indicator in ([Low],[High],[Avg])) p
order by
productid, VendorCode, date,
case time
when 'Morning' then 1
when 'Noon' then 2
when 'Evening' then 3
end
The case expression at the end of the order by clause makes sure the result is ordered correctly (Morning, Noon, Evening).
First do UNPIVOT then PIVOT
SELECT
piv.productid ,
piv.date ,
piv.VendorCode ,
piv.Tmp AS [Time],
piv.Low ,
piv.High ,
piv.Avg
from
(
select *
from #temptable
unpivot
(
[Time]
for [Tmp] in (morning, noon, evening)
) u
) src
pivot
(
min([Time])
for Indicator in ([Low], [High], [Avg])
) piv
Result:
productid date VendorCode Time Low High Avg
101 2016-08-05 202 evening 1 0 1
101 2016-08-05 202 morning 0 0 1
101 2016-08-05 202 noon 0 1 0
101 2016-08-06 202 evening 1 1 1
101 2016-08-06 202 morning 0 0 0
101 2016-08-06 202 noon 0 0 0

T-SQL cannot convert varcchar column to a numeric datatype

i have the following T-SQL statement:
select top 10 value1 from table1 where condition1 = 12345
result:
5449.0
228231.0
0.0
3128.0
6560.0
4541.0
2119.0
0.0
0.0
4183.0
the data type of value1 = "[char] (20) COLLATE Latin1_General_CS_AS NULL"
please note, each result line has 20 chars i.e. "5449.0______________" filled up with spaces.
I want to sum all this columns. how can i convert these values to a summable data type?
Use cast or convert:
-- for demo
declare #v char(20)
set #v = '228231.9 '
-- real magic
select cast(#v as real)
So this is the select in your case:
select cast(value1 as real) from table1 where condition1 = 12345
select sum(cast(value1 as real)) from table1 where condition1 = 12345

Get columns only if it is not null is sql server 2012?

I have the following rows.I dont want to select those columns whose entire value is null
col1 col2 col3
1 2 NULL
2 3 NULL
3 4 NULL
. . NULL
. . NULL
. . NULL
100 101 NULL
For example,
I want to select only col1 and col2 since all the values of col3 is null ie if col3 contains any value other than null then col1 col2 and col3 should be selected.Other wise col1 and col2 should only be selected.
How to acheive the above scenaria in sqlserver
There could be a better/efficient way present but you can try the below which is mixed o bit TSQL script and dynamic SQL. teasted and it works fine. A sample code below.
create table test1(col1 int,col2 int);
insert into test1(col1) values(2),(3),(4)
declare #col1sum int, #col2sum int, #countrow int;
-- This query will get you NULL count for all columns
select #col1sum = sum(case when col1 is null then 1 else 0 end),
#col2sum = sum(case when col2 is null then 1 else 0 end),
#countrow = count(1)
from test1;
select #col1sum, #col2sum, #countrow; --for display
declare #sql varchar(100);
-- check for column null count < total count of rows
if(#col1sum < #countrow)
set #sql = 'select col1 from test1';
else if(#col2sum < #countrow)
set #sql = 'select col2 from test1';
else
set #sql = 'select col1,col2 from test1';
exec(#sql); -- Finally execute the dynamic sql
If you want to go the way that David suggests in the comments and do the hiding in the UI, but have the database do the work to help you out, you can use aggregate functions with windows to add some extra columns:
declare #t table (col1 int,col2 int,col3 int)
insert into #t(col1,col2,col3) values
(1 ,2 ,NULL),
(2 ,3 ,NULL),
(3 ,4 ,NULL),
(9 ,NULL ,NULL),
(100 ,101 ,NULL)
select
col1,CASE WHEN MAX(col1) OVER () IS NULL THEN 0 ELSE 1 END as col1_HasValues,
col2,CASE WHEN MAX(col2) OVER () IS NULL THEN 0 ELSE 1 END as col2_HasValues,
col3,CASE WHEN MAX(col3) OVER () IS NULL THEN 0 ELSE 1 END as col3_HasValues
from #t
Which produces the result set:
col1 col1_HasValues col2 col2_HasValues col3 col3_HasValues
----------- -------------- ----------- -------------- ----------- --------------
1 1 2 1 NULL 0
2 1 3 1 NULL 0
3 1 4 1 NULL 0
9 1 NULL 1 NULL 0
100 1 101 1 NULL 0
The _HasValues columns will be identical across all rows and tells you if any row has a non-NULL value in the preceding column. If it's 0, you should hide the column in the UI.

Extract multiple numeric values from string with T-SQL

I have a column with data in a special “format”. Example:
L100000
L50
L5
S10
S15L10
S20
S90
S10
S10L5
S10L40
S10L5
The value consists of an “S” and/or an “L”, each with a number following the letter.
I need to write a query, which will return two columns, “S” and “L”, which will have only the coresponding numeric value following the letter.
The above example should look like this:
S L
======== ==========
0 100000
0 50
0 5
10 0
15 10
20 0
90 0
10 0
10 5
10 40
10 5
If no "S" or "L" is found, the default value is zero.
try this:
DECLARE #YourTable table (RowValue varchar(30))
INSERT INTO #YourTable VALUES ('L100000')
INSERT INTO #YourTable VALUES ('L50')
INSERT INTO #YourTable VALUES ('L5')
INSERT INTO #YourTable VALUES ('S10')
INSERT INTO #YourTable VALUES ('S15L10')
INSERT INTO #YourTable VALUES ('S20')
INSERT INTO #YourTable VALUES ('S90')
INSERT INTO #YourTable VALUES ('S10')
INSERT INTO #YourTable VALUES ('S10L5')
INSERT INTO #YourTable VALUES ('S10L40')
INSERT INTO #YourTable VALUES ('S10L5')
SELECT
CASE
WHEN LocationS>0 AND LocationL=0 THEN RIGHT(RowValue,Length-1)
WHEN LocationS>0 THEN SUBSTRING(RowValue,2,LocationL-2)
ELSE NULL
END AS S
,CASE
WHEN LocationS=0 AND LocationL>0 THEN RIGHT(RowValue,Length-1)
WHEN LocationS>0 AND LocationL>0 THEN RIGHT(RowValue,Length-LocationL)
ELSE NULL
END AS L
,RowValue
FROM (SELECT
RowValue
,CHARINDEX('S',RowValue) AS LocationS
,CHARINDEX('L',RowValue) AS LocationL
,LEN(RowValue) AS Length
FROM #YourTable
) dt
OUTPUT
S L RowValue
------------------------------ ------------------------------ --------------
NULL 100000 L100000
NULL 50 L50
NULL 5 L5
10 NULL S10
15 10 S15L10
20 NULL S20
90 NULL S90
10 NULL S10
10 5 S10L5
10 40 S10L40
10 5 S10L5
(11 row(s) affected)
if you have loads of data give this a try, it may be faster (has same output, basically removed the derived table and made everything use inline functions):
SELECT
CASE
WHEN CHARINDEX('S',RowValue)>0 AND CHARINDEX('L',RowValue)=0 THEN RIGHT(RowValue,LEN(RowValue)-1)
WHEN CHARINDEX('S',RowValue)>0 THEN SUBSTRING(RowValue,2,CHARINDEX('L',RowValue)-2)
ELSE NULL
END AS S
,CASE
WHEN CHARINDEX('S',RowValue)=0 AND CHARINDEX('L',RowValue)>0 THEN RIGHT(RowValue,LEN(RowValue)-1)
WHEN CHARINDEX('S',RowValue)>0 AND CHARINDEX('L',RowValue)>0 THEN RIGHT(RowValue,LEN(RowValue)-CHARINDEX('L',RowValue))
ELSE NULL
END AS L
,RowValue
FROM #YourTable
SELECT
SVal = CASE
WHEN PATINDEX('S%L%', TextVal) > 0 THEN REPLACE(LEFT(TextVal, CHARINDEX('L', TextVal) - 1), 'S', '')
WHEN PATINDEX('S%', TextVal) > 0 THEN REPLACE(TextVal, 'S', '')
ELSE '0'
END,
LVal = CASE
WHEN PATINDEX('S%L%', TextVal) > 0 THEN REPLACE(RIGHT(TextVal, LEN(TextVal) - CHARINDEX('L', TextVal)), 'L', '')
WHEN PATINDEX('L%', TextVal) > 0 THEN REPLACE(TextVal, 'L', '')
ELSE '0'
END
FROM StringList
Assumes S always comes before L. Also you might want to cast the results as numbers (they are strings now) depending on what you need for the output.
I would suggest a clr-based function which would use a regex to extract the S or L value from the string. You could use it like this:
insert new_table (s_value, l_value)
select getValue('S', original_value), getValue('L', original_value)
from original_table
not tested but should be close assuming s always appears before l:
select
case when charindex(data, 's') <> 0 then
substr(data, charindex(data, 's'), charindex(data ,'l'))
else 0 end
, case when charindex(data, 'l') <> 0 then
substr(data, charindex(data, 'l'))
else 0 end
from some_table

Resources