Selecting varchar values from a column - sql

I'm working on SQL 2008 and have a table with 1000's of codes in it - a sample would be:
D37
D37.0
D38
D38.0
D39
D39.0
D3A
D3A.0
D40
What I need to do is select the values between D37 and D40. However, I do not want the D3A values (or D3B or D3C for that matter). I have tried the following:
SELECT Code
FROM Table
WHERE Code BETWEEN 'D37' AND 'D40'
However, this get all the codes listed above, including the D3A codes.
Is there a way to exclude the codes that do not fall in the 37-40 range?

Assuming that the single-letter convention is followed throughout, and there aren't any more weird characters than shown in the data, you can do this:
WITH cte AS (
[MyColumn]
, SELECT SUBSTRING([MyColumn],2,LEN([MyColumn)-1) AS Code
FROM MyTable
WHERE ISNUMERIC(SUBSTRING([MyColumn],2,LEN([MyColumn)-1)=1
)
SELECT [MyColumn]
FROM cte
WHERE CAST(Code AS float) BETWEEN 37 AND 40

It's messy, but this should do what you are asking.
SELECT code
from Mytable
where
ISNUMERIC( SUBSTRING(code, 2, (len(code)) ) ) > 0
and convert(float, SUBSTRING(code, 2, (len(code))) ) between 37 and 40

Related

Filter IDs with just numbers excluding letters

So I have results that begins with 2 letters followed by 3 numbers, for example:
ID_Sample
AB001
BC003
AB100
BC400
How can I do a query that ignores the letters and just looks up the numbers to do a filter? For example:
WHERE ID_Sample >= 100
I tried using a "Replace" to get rid of known letters, but I figured there might be a better way. For example:
Select
Replace(id_sample,'AB','')
Choosing the 3 numerals on the right would work too.
For your sample data, you can just start at the third character and convert to a number:
where try_convert(int, stuff(ID_Sample, 1, 2, '')) > 100
Or, if you know that the number is 3 characters:
where try_convert(int, right(ID_Sample, 3)) > 100
+1 for Gordon's answer. This is a fun problem that you can solve using TRANSLATE if you're using SQL 2017+.
First, in case you've never used it, Per BOL TRANSLATE:
Returns the string provided as a first argument after some characters
specified in the second argument are translated into a destination set
of characters specified in the third argument.2
This:
SELECT TRANSLATE('123AABBCC!!!','ABC','XYZ');
Returns: 123XXYYZZ!!!
Here's the solution using TRANSLATE:
-- Sample Data
DECLARE #t TABLE (ID_Sample CHAR(6))
INSERT #t (ID_Sample) VALUES ('AB001'),('BC003'),('AB100'),('BC400'),('CC555');
-- Solution
SELECT
ID_Sample = t.ID_Sample,
ID_Sample_Int = s.NewString
FROM #t AS t
CROSS JOIN (VALUES('ABCDEFGHIJKLMNOPQRSTUVWXYZ', REPLICATE(0,26))) AS f(S1,S2)
CROSS APPLY (VALUES(TRY_CAST(TRANSLATE(t.ID_Sample,f.S1,f.S2) AS INT))) AS s(NewString)
WHERE s.NewString >= 100;
Without the WHERE clause filter you get:
ID_Sample ID_Sample_Int
--------- -------------
AB001 1
BC003 3
AB100 100
BC400 400
CC555 555
... the WHERE clause filters out the first two rows.
Check these methods- Unit test also done!
Declare #Table as table(ID_Sample varchar(20))
set nocount on
Insert into #Table (ID_Sample)
Values('AB001'),('BC003'),('AB100'),('BC400')
--substring_method
select * from #Table
where try_cast(substring(ID_Sample,3,3) as int) >100
--right_method
select * from #Table
where try_cast(right(ID_Sample,3) as int) >100
--stuff_method
select * from #Table
where try_cast(stuff(ID_Sample,1,2,'') as int) >100
--replace_method
select * from #Table
where try_cast(replace(ID_Sample,left(ID_Sample,2),'') as int) >100

Insert into sql Max +1 only numbers (prevent characters)

I'm using this code
(SELECT (MAX(CODE) +1 WHERE ISNUMERIC([code]) = 1)
I want to max +1 only my numbers of my column preventing characters characters.
NOTE: THIS QUESTION WAS TAGGED MYSQL WHEN THIS ANSWER WAS POSTED.
You can use substring_index() to split the values and then re-unite them:
(SELECT CONCAT(SUBSTRING_INDEX(MAX(Code), '-', 1), '-',
SUBSTRING_INDEX(MAX(CODE), '-', -1) + 1
)
FROM . . .
WHERE code LIKE '%NEW-1%'
)
This assumes that the wildcards do not have hyphens in them, and that the values after the "1" are all numbers.
Also, this doesn't pad the number is zeroes, but that is a good idea for such codes -- it ensures that they are always the same length and that they sort correctly.
The MAX() function accepts expressions, not just column names:
SELECT MAX(CASE ISNUMERIC(code) WHEN 1 THEN code END)+1 as next_code
FROM (
SELECT '15' AS code
UNION ALL SELECT ' 98 ' AS code
UNION ALL SELECT 'New-45' AS code
) foo
WHERE ISNUMERIC(code)=1;
16
(Link is to SQL Server 2005, docs for SQL Server 2000 are apparently no longer on line, but MAX() belongs to SQL standard anyway.)

Converting SQL varchar column values to $ format i.e. thousand separation

I have a varchar(256) column AttributeVal with all different type of text values.
I need to find out all $ values like $5000, $2000 etc & add thousand separator to them (only to these values, but not to the other text values present in that column).
Thus the updated values should look like $5,000 & $2,000.
If I am using following query, then it will end up converting all values & I need to concatenate $ manually :(
replace(convert(varchar, convert(Money, AttributeVal), 1), '.00', '')
NB : I know that these kind of formatting should be taken care in the application end, but our customer is adamant to have these customization to be stored in DB only.
I don't think you can do a replace statement based on a regular expression like that exactly. See this stackoverflow post asking the same question.
You may want to reinforce to your client that formatted data should not be stored in a database. That money value should probably be stored in a DECIMAL(13, 4) or something similar instead of a VARCHAR field mixed with other data as well.
Your question is a great example of why you don't want to do this. It makes simple things very difficult.
Try this
SELECT '$'+ PARSENAME( Convert(varchar,Convert(money,convert(Money, 100000)),1),2)
Output: $100,000
Hope this help!
try with this, this will take care of thousand separator :-)
'$'+convert(varchar(50), CAST(amount as money), -1) amount
Sample
;with cte (amount)
as
(
select 5000 union all
select 123254578.00 union all
select 99966.00 union all
select 0.00 union all
select 6275.00 union all
select 18964.00 union all
select 1383.36 union all
select 26622.36
)
select '$'+convert(varchar(50), CAST(amount as money), -1) amount
from cte
Here is my take on the problem:
select coalesce(cast(try_convert(money, value) as varchar(50)), value) converted
from (
values ('50')
, ('5000')
, ('3000.01')
, ('text')
) samples(value)
and the output:
converted
--------------------------------------------------
50.00
5000.00
3000.01
text
(4 row(s) affected)

Conversion failed when converting the varchar value 'ADMIN' to data type int

I have sql like below. Home hints:
Results in K table (from WITH) gives number codes of specified range (ex.: 1-90).
The main select part works fine until I use
sum(F._IsInIntersection) [CountIntersection]
It causes error
Msg 245, Level 16, State 1, Line 11
Conversion failed when converting the varchar value 'ADMIN' to data type int.
If I comment this line, it is OK.
I do not know, why this error occurs the line with SUM() contains only int values. No ADMIN value (as mentioned in the error) exists anywhere...
Can anyone see any problems with the query?
;with K as (
select cast(c.Code as int) code
from rmCategory c, rmCategoryGroup cg, rmIdentification ic
where 1=1
and c.CategoryGroupID=cg.ID
and c.ID=ic.ID0
)
select
F.STAV_AKT [Code]
, count(F.STAV_AKT) [Count]
, sum(F._IsInIntersection) [CountIntersection]
from
(
select
f.*
, case when f.KVALIF IN (select code from K) and f.KVALIF is not null then 1 else 0 end _IsInIntersection
from frmFormData_208629_MaMo2_IMPORT f, rmIdentification i
where 1=1
and f.ID=i.id0
and i.isValid=1
and f.sysDAVKA=5
) F
group by F.STAV_AKT
order by F.STAV_AKT
I also tried CASTing parameter inside of sum(cast(F._IsInIntersection as int)) [CountIntersection] to be sure to use int values instead of the boolean ones, but no change.
Martin, I'm suspecting that c.Code also contains the value 'ADMIN' in the part
cast(c.Code as int) code
It runs good without the SUM because it's part of a CTE and is not materialized when the column is not used.
If for example I run the following code example in Fiddle it runs fine, but if I also select the column Code it fails when trying to CAST 'ADMIN' to INT (Fiddle).
;WITH cte as
(
select CAST(a AS INT) AS Code
,'Dummy' AS Column2
FROM (
SELECT 1 AS a
UNION ALL SELECT 'a'
) t
)
SELECT Column2
--,Code
FROM cte
So try to figure out what exactly the values for column Code are by using e.g.
SELECT DISTINCT Code FROM rmCategory
What is the datatype of f.sysDAVKA?
Try running
SELECT f.sysDAVKA
FROM frmFormData_208629_MaMo2_IMPORT f
WHERE f.sysDAVKA = 'ADMIN'
My gut feeling is you will find at least one row. If this is true, then changing your WHERE clause to
where 1=1
and f.ID=i.id0
and i.isValid=1
and f.sysDAVKA=CAST(5 AS char(1))
should resolve the problem.

How to find out the length of an expression within a column in SQL Server 2008

I am not a database administrator but I often have to query databases to do my job. Recently I've been tasked with querying for the length of a semi-colon separated expression within a database column. It will probably be easier to show as a made-up example table and column:
Table is Table1.
Column is Column1.
Values of two rows in Table1.Column1 look like this:
principal_name='Joe Schmoe'; marital_status='m'; shoe_size='12.5';
message='This is a message which is 45 characters long';
years_active='15'
principal_name='Jim Schmim'; marital_status='s'; shoe_size='10.5';
message='This is a xxxxxxxxxxx message which is 57 characters long';
years_active='6'
I need to query Table1.Column1 and find out out how many rows have more than 50 characters in the message portion of this column.
If this column only had a single value, I could just use something like:
SELECT COUNT(*) FROM Table1 WHERE LEN(column1) > 40
However, I don't need to know how many total characters the field has, only how many are between message= and ;
I have never dealt with a column that has multiple values separated by semicolons before, so I don't know how to query for what I need to know.
Assuming there's always the same parts within column1, in the same order, something like
where ( CharIndex('years_active=',column1) - CharIndex('message=',column1) ) >50
(give or take some adjustments for lengths of descriptions, etc)
You can try something like this in a custom function
Declare #str varchar(max);
set #str = 'aaaabc=thisisatest;aaaaa'
select LEN(substring(#str,CHARINDEX('=',#str,0)+1, CHARINDEX(';',#str,0)-CHARINDEX('=',#str,0)-1))
Try this
;with cte as
(
select 'principal_name=''Joe Schmoe''; marital_status=''m''; shoe_size=''12.5'';message=''This is a message which is 45 characters long'';years_active=''15''' as column1
union
select 'principal_name=''Jim Schmim''; marital_status=''s''; shoe_size=''10.5''; message=''This is a xxxxxxxxxxx message which is 57 characters long''; years_active=''6'''
),
cte2 as
(
SELECT ltrim(rtrim(r.value('.','VARCHAR(MAX)'))) as Item from (
select CONVERT(XML, N'<root><r>' + REPLACE(column1,';','</r><r>') + '</r></root>') as XmlString
from cte ) x
CROSS APPLY x.XmlString.nodes('//root/r') AS RECORDS(r)
)
--SELECT *, LEN(item) - 10 from cte2 x where x.Item like 'message=%' and LEN(item) > 50
SELECT COUNT(*) cnt from cte2 x where x.Item like 'message=%' and LEN(item) > 50