I have my table data sums as follows
---------------------
Building | Area m2
---------------------
|Dante 12 | 10
|Dante 10 | 5
|Dante 9 | 2
|Crandley | 20
|Bence | 30
I want to sum Building Area but buildings like '%dante%' I want to combine into sum "Dante" like below:
-------------------
Building | Area m2
-------------------
Dante | 17
Crandley | 20
Bence | 30
Group by with case will do the trick for sample data given,like of this type can use index as well
Select
case when building like 'dante%' then 'Dante' else building end,
sum([area m2])
from
table
group by
case when building like 'dante%' then 'Dante' else building end
if there are numbers for other columns,you can strip out the numbers first and do the rest of stuff like below
;with cte
as
(select REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE (building, '0', ''),
'1', ''),
'2', ''),
'3', ''),
'4', ''),
'5', ''),
'6', ''),
'7', ''),
'8', ''),
'9', '') as bulding,aream2
from #temp
)
select building,sum(aream2)
from
cte
group by
building
References:
Remove numbers found in string column
Works only if numeric value is to be removed
Numeric value is to be replaced (Nested replace function can go upto 32 level deep) and group by column.
SELECT x.Building, SUM(x.AreaM2) AS [Area m2]
FROM (
SELECT
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE (Building, '0', '')
,'1', '')
,'2', '')
,'3', '')
,'4', '')
,'5', '')
,'6', '')
,'7', '')
,'8', '')
,'9', '') [Building], AreaM2 FROM Buildings) AS x
GROUP BY x.Building
Related
I am trying to reformat around 1000 phone numbers in a SQL Server database to US format (###) ###-####
Currently the phone numbers are formatted in all sorts of ways ranging from ##########, ###-###-####, one is ###)-###-####. There is also one with only six digits.
As a first step I've been attempting to isolate the numbers in all of these rows but its just returning the same as they were already.
select SUBSTRING(phone, PATINDEX('%[0-9]%', phone), LEN(phone)) from people
How could I best go about writing a query which would format them all as (###) ###-####?
expected output:
(555) 222-3333
(555) 444-3030
(555) 092-0920
(555) 444-4444
Since one suggestion was made already and the suggestion there to isolate numbers in a string uses a while loop I need to post an alternative to that which doesn't use any looping. Instead it utilizes a tally or numbers table. There are lots of solutions for those. I like to use a view which is lightning fast and has zero reads.
Here is my version of a tally table.
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
Next we need a table valued function to remove the characters that are not numbers using our tally table. This is also super fast because we are using our tally table instead of looping.
create function GetOnlyNumbers
(
#SearchVal varchar(8000)
) returns table as return
with MyValues as
(
select substring(#SearchVal, N, 1) as number
, t.N
from cteTally t
where N <= len(#SearchVal)
and substring(#SearchVal, N, 1) like '[0-9]'
)
select distinct NumValue = STUFF((select number + ''
from MyValues mv2
order by mv2.N
for xml path('')), 1, 0, '')
from MyValues mv
Now that we have all the legwork done we can focus on the task at hand. Since you didn't provide any sample data I just made up some stuff. I am not really sure if this is representative of your data or not but this works on the sample data I created.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something(SomeVal varchar(100))
insert #Something values
('Maybe you have other stuff in here. 5552223333 additional characters can cause grief')
, ('321-654-9878')
, ('123)-333-4444')
, ('1234567')
select replace(format(try_convert(bigint, n.NumValue), '(###) ###-####'), '() ', '')
, n.NumValue
from #Something s
cross apply dbo.GetOnlyNumbers(s.SomeVal) n
The output for the formatted data looks like this:
(555) 222-3333
(321) 654-9878
(123) 333-4444
123-4567
If this reformatting something that is going to be used repeatedly then a creating a UDF as suggested by #GSerg would be the way to go.
If this is just a one time clean-up you could give this a try.
First replace all of the numbers with empty strings with a series of nested REPLACE() functions.
DECLARE #PhoneNumbers TABLE (
Number varchar (20))
INSERT INTO #PhoneNumbers VALUES ('(888-239/1239')
INSERT INTO #PhoneNumbers VALUES ('222.1234')
SELECT
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(Number, '0', '')
, '1', '')
, '2', '')
, '3', '')
, '4', '')
, '5', '')
, '6', '')
, '7', '')
, '8', '')
, '9', '')
FROM #PhoneNumbers
Then take those result non-numeric characters and put them each in their own nested REPLACE() function and format the result. You will have to deal with each length individually. If you have only 7 digits and you want to format it to have 10 digits what do you want those extra 3 digits to be. This will handle the 10 digit phone numbers.
SELECT FORMAT(x.NumbersOnly, '(###) ###-####')
FROM
(
SELECT
CONVERT(BIGINT,
REPLACE(
REPLACE(
REPLACE(
REPLACE(Number, '(', '')
, '-', '')
, '/', '')
, '.', '')
) AS NumbersOnly
FROM #PhoneNumbers
) x
WHERE LEN(x.NumbersOnly) = 10
Here is the dbfiddle.
For ex : if sql column value is sa,123k and the output should first three characters i.e. sak
Letters and any special characters needs to be eliminated and gets only three characters. How do we do this ?
You can use recursive CTEs for this purpose:
with t as (
select 'sa,123k' as str
),
cte as (
select str, left(str, 1) as c, stuff(str, 1, 1, '') as rest, 1 as lev,
convert(varchar(max), (case when left(str, 1) like '[a-zA-Z]' then left(str, 1) else '' end)) as chars
from t
union all
select str, left(rest, 1) as c, stuff(rest, 1, 1, '') as rest, lev + 1,
convert(varchar(max), (case when left(rest, 1) like '[a-zA-Z]' then chars + left(rest, 1) else chars end))
from cte
where rest > '' and len(chars) < 3
)
select str, max(chars)
from cte
where len(chars) <= 3
group by str;
Here is a db<>fiddle.
This might help
DECLARE #VAR VARCHAR(100)= 'sa,1235JSKL', #RESULT VARCHAR(MAX)=''
SELECT #RESULT = #RESULT+
CASE WHEN RESULT LIKE '[a-zA-Z]' THEN RESULT ELSE '' END
FROM (
SELECT NUMBER, SUBSTRING(#VAR,NUMBER,1) AS RESULT
FROM MASTER..spt_values
WHERE TYPE = 'P' AND NUMBER BETWEEN 1 AND LEN(#VAR)
)A
ORDER BY NUMBER
SELECT SUBSTRING(#RESULT,1,3)
If you want to apply this on a Tables column, you need to create Scalar function with same logic. You can find more number of articles how to create the scalar function by Googling..
You can use this function which is written by G Mastros to do this.
Create Function [dbo].[RemoveNonAlphaCharacters](#Temp nvarchar(MAX))
Returns nvarchar(MAX)
AS
Begin
Declare #KeepValues as nvarchar(MAX)
Set #KeepValues = '%[^a-z]%'
While PatIndex(#KeepValues, #Temp) > 0
Set #Temp = Stuff(#Temp, PatIndex(#KeepValues, #Temp), 1, '')
Return #Temp
End
Then simply call the fuction like this
SELECT LEFT(dbo.RemoveNonAlphaCharacters(colName), 3)
FROM TableName
Reference: G Mastros answer on "How to strip all non-alphabetic characters from string in SQL Server" question.
Well, this is ugly, but you could replace all the characters you don't like.
In your example, this would be:
SELECT REPLACE (REPLACE (REPLACE (REPLACE ('sa,123k', '1', ''), '2', ''), '3', ''), ',', '')
Obviously, this needs a lot of replaces if you need all numbers and other sorts of characters replaced.
Edited, based on your comment:
SELECT REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE ('123456gh,.!879k', '1', ''), '2', ''), '3', ''), ',', ''), '4', ''), '5', ''), '6', ''), '.', ''), '!', ''), '7', ''), '8', ''), '9', '')
How Can I separate characters and number from a word using SQL Server query?
Example word: AB12C34DE
The Output is like:
col1
-----
ABCDE
col2
-----
1234
Please try this.
DECLARE #Numstring varchar(100)
SET #Numstring = 'AB12C34DE'
WHILE PATINDEX('%[^0-9]%',#Numstring) <> 0.
SET #Numstring = STUFF(#Numstring,PATINDEX('%[^0-9]%',#Numstring),1,'')
SELECT #Numstring As Number
DECLARE #Charstring varchar(100)
SET #Charstring = 'AB12C34DE'
WHILE PATINDEX('%[^A-Z]%',#Charstring) <> 0.
SET #Charstring = STUFF(#Charstring,PATINDEX('%[^A-Z]%',#Charstring),1,'')
SELECT #Charstring As Character
Try it like this:
DECLARE #word VARCHAR(100)='AB12C34DE';
WITH Tally(Nmbr) AS
(
SELECT TOP(LEN(#word)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values
)
,Separated AS
(
SELECT CASE WHEN OneChar LIKE '[0-9]' THEN 1 ELSE 0 END AS IsDigit
,OneChar
,Nmbr
FROM Tally
CROSS APPLY(SELECT SUBSTRING(#word,Nmbr,1)) A(OneChar)
)
SELECT (SELECT OneChar AS [*] FROM Separated WHERE IsDigit=1 ORDER BY Nmbr FOR XML PATH(''),TYPE).value('.','nvarchar(max)') AS AllNumbers
,(SELECT OneChar AS [*] FROM Separated WHERE IsDigit=0 ORDER BY Nmbr FOR XML PATH(''),TYPE).value('.','nvarchar(max)') AS AllCharacters;
Some explanation
The idea uses a tally table (a list of numbers). You might use an existing physical numbers table...
The first CTE "Tally" will create a derived list of numbers (1,2,3, ...), one for each character.
The second CTE will read each character one-by-one and mark it as digit or not.
The final query will re-concatenate the list of characters
As you are using SQL Server 2012 so you can't use TRANSLATE which can simplify this.
One ways is to use REPLACE like following. If you want you can convert it to a user defined function so that you don't have to write same thing again and again.
DECLARE #TABLE TABLE(VAL VARCHAR(100))
INSERT INTO #TABLE SELECT 'AB12C34DE'
SELECT REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE (VAL, '0', ''),
'1', ''),
'2', ''),
'3', ''),
'4', ''),
'5', ''),
'6', ''),
'7', ''),
'8', ''),
'9', '') COL1,
REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE (VAL, 'A', ''),
'B', ''),
'C', ''),
'D', ''),
'E', ''),
'F', ''),
'6', ''),
'G', ''),
'H', ''),
'I', '') COL2
--ADD OTHER CHARACTERS
FROM #TABLE
This seems like a good place to use a recursive CTE:
with cte as (
select v.str, convert(varchar(max), '') as digits, convert(varchar(max), '') as chars, 1 as lev
from (values ('AB12C34DE')) v(str)
union all
select stuff(str, 1, 1, ''),
(case when left(str, 1) like '[0-9]' then digits + left(str, 1) else digits end),
(case when left(str, 1) like '[a-zA-Z]' then chars + left(str, 1) else chars end),
lev + 1
from cte
where str > ''
)
select top (1) with ties cte.*
from cte
order by row_number() over (order by lev desc);
As the values() clause suggests, this will work on columns in a table as well as constants.
I have a table containing values like this:
+----+------------------------------------------------+
| ID | AssignedTo |
+----+------------------------------------------------+
| 1 | 92;#Alex Smith;#114;#Joe Day;#184;#Johnny Bone |
+----+------------------------------------------------+
And I would like to remove the "[number];#" and replace it for a single dash "-" for every occurrence
+----+------------------------------------+
| ID | AssignedTo |
+----+------------------------------------+
| 1 | Alex Smith - Joe Day - Johnny Bone |
+----+------------------------------------+
Is this possible with default SQL Server 2012 functions?
Thanks!
You can use PATINDEX and stuff for doing this... but I am still not looking for options without looping...
DECLARE #var varchar(100) = '92;#Alex Smith;#114;#Joe Day;#184;#Johnny Bone'
WHILE (PATINDEX('%[0-9]%', #var) > 0)
BEGIN
SELECT
#var = STUFF(#var, PATINDEX('%[0-9]%', #var), 1, '')
END
SELECT REPLACE(REPLACE(#var, ';#;#', ' - '), ';#', '')
If the names will never have numbers in them, you could do:
SELECT final.AssignedTo
FROM Tab t
CROSS APPLY (SELECT REPLACE(t.AssignedTo, '0', '') AS AssignedTo) r0
CROSS APPLY (SELECT REPLACE(r0.AssignedTo, '1', '') AS AssignedTo) r1
CROSS APPLY (SELECT REPLACE(r1.AssignedTo, '2', '') AS AssignedTo) r2
CROSS APPLY (SELECT REPLACE(r2.AssignedTo, '3', '') AS AssignedTo) r3
CROSS APPLY (SELECT REPLACE(r3.AssignedTo, '4', '') AS AssignedTo) r4
CROSS APPLY (SELECT REPLACE(r4.AssignedTo, '5', '') AS AssignedTo) r5
CROSS APPLY (SELECT REPLACE(r5.AssignedTo, '6', '') AS AssignedTo) r6
CROSS APPLY (SELECT REPLACE(r6.AssignedTo, '7', '') AS AssignedTo) r7
CROSS APPLY (SELECT REPLACE(r7.AssignedTo, '8', '') AS AssignedTo) r8
CROSS APPLY (SELECT REPLACE(r8.AssignedTo, '9', '') AS AssignedTo) r9
CROSS APPLY (SELECT REPLACE(r9.AssignedTo, ';#;#', ' - ') AS AssignedTo) sep
CROSS APPLY (SELECT REPLACE(sep.AssignedTo, ';#', '') AS AssignedTo) final
The CROSS APPLYs just cleanup the nested REPLACEs. You could also just do REPLACE(REPLACE(REPLACE(...), '1', ''), '2', '')...)';#', '').
I want to remove dots (.) before decimal places in my amount value. Below is my database table
Query
SELECT sum( REPLACE( REPLACE( amt, ',', '' ) , ' ', '' ) ) FROM amt_demo
when I run the above query I get the following output.
Output
But I want the total sum of the values like:
1333.00
100000.50
100000.00
123456789
123456789
123456789
---------------
370571700.50
Any idea how can I solve this?
Use Maths CEIL function
SELECT CEIL(sum( REPLACE( REPLACE( amt, ',', '' ) , ' ', '' ) ))