Is first character of varchar a string? - sql

How can I achieve the below to show all rows where the first character of the ClientNumber is not a letter of the alphabet?
select * from Table
where Left(ClientNumber,1) <> A to Z

You can simply do:
where left(clientNumber, 1) < 'A' or left(clientNumber, 1) > 'Z'
or:
where left(clientNumber, 1) not between 'A' and 'Z'
Do note, however, that the comparison will be tricky because of character case. Assuming 1-byte characters, you might want:
where ascii(left(clientNumber, 1)) not between ascii('A') and ascii('Z')
EDIT:
If I wanted to use an index:
where clientNumber < 'A' or clientNumber > 'Z['
However, I'm not so sure an index is really useful in this case.

You can use NOT LIKE:
SELECT *
FROM Table
WHERE ClientNumber NOT LIKE '[A-Za-z]%'

Try it like this...
SELECT
*
FROM
dbo.MyTable mt
WHERE
mt.ClientNumber LIKE '[^a-Z]%'

Related

Print each character of a word line by line using a SQL query

I am giving input word is "hello"
My output will be print as mentioned below using SQL query not pl/sql.
h
e
l
l
o
You can use SUBSTR() function within a hierarchical query such as
SELECT SUBSTR(col,level,1) AS "letters"
FROM t
CONNECT BY level <= LENGTH(col)
presuming your DB is Oracle from the keyword PL/SQL
Use like this
select substring(a.b, v.number+1, 1)
from (select 'hellow' b) a
join master..spt_values v on v.number < len(a.b)
where v.type = 'P'
You didn't mention your DBMS, but in Postgres you can use:
select *
from unnest(string_to_array('hello', null));
Here is another way to do this in oracle
select 'hello'
,substr('hello',rownum,1) as vertical_str
from dual a
join all_tables b
on 1=1
where rownum<=length('hello')
h
e
l
l
o
Another option is a recursive CTE.
WITH
word
(word)
AS
(
SELECT 'hello' word
FROM dual
),
letter
(letter,
remainder)
AS
(
SELECT substr(word, 1, 1) letter,
substr(word, 2) remainder
FROM word
UNION ALL
SELECT substr(remainder, 1, 1) letter,
substr(remainder, 2) remainder
FROM letter
WHERE remainder IS NOT NULL
)
SELECT letter
FROM letter;
db<>fiddle
I am assuming Oracle here as you mentioned PL/SQL. But for other DBMS this would be pretty similar -- the substr() function might be called substring(), instead of a NULL you'd have to check for remainder to be the empty string and the RECURESIVE keyword might be needed for the second CTE.

Oracle SQL - group by char cast

Using the a char-cast in a group-by clause results something unexpected:
select cast(col as char(2)) from (
select 'Abc' as col from dual
union all
select 'Abc' as col from dual
) group by cast(col as char(10));
The result is 'Abc ' (10 characters long).
Intuitively, I would have expected Oracle to return one of the following:
An error: 'not a group-by expression', as the group-by clause is another than the selection clause
A result of length 2 'Ab'.
Replacing cast(col as char(2)) with cast(col as char(3)), Oracle returns an error 'not a group-by expression'. This, again is a very strange behavior.
How can this be explained? What's the reason behind it?
I'm using Oracle SQL 11g.
As was mentioned above, I think there is a misunderstanding going on. o.O
I can't explain why it's doing this, but here's the pattern for the type of query you have:
If you generalize it a bit like this, where [A] and [B] are integers, and [STRING] is whatever text you want:
select cast(col as char([A])) from (
select '[STRING]' as col from dual
union all
select '[STRING]' as col from dual
) group by cast(col as char([B]));
it looks like this always fails if one of the two conditions below is true (there may be others):
( LENGTH([STRING]) < [B] OR LENGTH([STRING] > [B]) and [A] = LENGTH([STRING])
( LENGTH([STRING]) = [B] AND [A] <> LENGTH([STRING]) )
Otherwise, it'll return a row.
But if you take your example that runs and use it in a CREATE TABLE statement, it's going to fail as it sets up the column width to be the 2 and can't fit the 3 character string coming in.
To add to the oddity, if you append something at the start and the end of the string like this:
select '\*'||cast(col as char([A]))||'\*' from (
select '[STRING]' as col from dual
union all
select '[STRING]' as col from dual
) group by cast(col as char([B]));
This will only work if [A] >= [B], otherwise it fails on ORA-01489: result of string concatenation is too long.
Curious...

Query table by string matching without using LIKE?

How can I query a table where first name starts with 'N' and last name starts with 'K' without using like?
Try something like the following:
SELECT * FROM mytable
WHERE SUBSTR(firstName, 1, 1) = 'N'
AND SUBSTR(lastName, 1, 1) = 'K';
you might try with > and < operators
e.g.:
WHERE NAME >= 'N' AND NAME < 'O'
but I don't guarantee you get each and every letter you would expect (especially with accentuated characters if any)
Scal
What about regular Expression ?
select * from table1 where regexp_like ( firstName, '^N*');
select * from table1 where regexp_like ( lastName, '^K*');

Get SQL Substring After a Certain Character but before a Different Character

I have some key values that I want to parse out of my SQL Server table. Here are some examples of these key values:
R50470B50469
B17699C88C68AM
R22818B17565C32G16SU
B1444
What I am wanting to get out of the string, is all the numbers that occur after the character 'B' but before any other letter character if it exists such as 'C'. How can I do this in SQL?
WITH VALS(Val) AS
(
SELECT 'R50470B50469' UNION ALL
SELECT 'R22818B17565C32G16SU' UNION ALL
SELECT 'R22818B17565C32G16SU' UNION ALL
SELECT 'B1444'
)
SELECT SUBSTRING(Tail,0,PATINDEX('%[AC-Z]%', Tail))
FROM VALS
CROSS APPLY
(SELECT RIGHT(Val, LEN(Val) - CHARINDEX('B', Val)) + 'X') T(Tail)
WHERE Val LIKE '%B%'

How do I sort a VARCHAR column in SQL server that contains numbers?

I have a VARCHAR column in a SQL Server 2000 database that can contain either letters or numbers. It depends on how the application is configured on the front-end for the customer.
When it does contain numbers, I want it to be sorted numerically, e.g. as "1", "2", "10" instead of "1", "10", "2". Fields containing just letters, or letters and numbers (such as 'A1') can be sorted alphabetically as normal. For example, this would be an acceptable sort order.
1
2
10
A
B
B1
What is the best way to achieve this?
One possible solution is to pad the numeric values with a character in front so that all are of the same string length.
Here is an example using that approach:
select MyColumn
from MyTable
order by
case IsNumeric(MyColumn)
when 1 then Replicate('0', 100 - Len(MyColumn)) + MyColumn
else MyColumn
end
The 100 should be replaced with the actual length of that column.
There are a few possible ways to do this.
One would be
SELECT
...
ORDER BY
CASE
WHEN ISNUMERIC(value) = 1 THEN CONVERT(INT, value)
ELSE 9999999 -- or something huge
END,
value
the first part of the ORDER BY converts everything to an int (with a huge value for non-numerics, to sort last) then the last part takes care of alphabetics.
Note that the performance of this query is probably at least moderately ghastly on large amounts of data.
select
Field1, Field2...
from
Table1
order by
isnumeric(Field1) desc,
case when isnumeric(Field1) = 1 then cast(Field1 as int) else null end,
Field1
This will return values in the order you gave in your question.
Performance won't be too great with all that casting going on, so another approach is to add another column to the table in which you store an integer copy of the data and then sort by that first and then the column in question. This will obviously require some changes to the logic that inserts or updates data in the table, to populate both columns. Either that, or put a trigger on the table to populate the second column whenever data is inserted or updated.
SELECT *, CONVERT(int, your_column) AS your_column_int
FROM your_table
ORDER BY your_column_int
OR
SELECT *, CAST(your_column AS int) AS your_column_int
FROM your_table
ORDER BY your_column_int
Both are fairly portable I think.
you can always convert your varchar-column to bigint as integer might be too short...
select cast([yourvarchar] as BIGINT)
but you should always care for alpha characters
where ISNUMERIC([yourvarchar] +'e0') = 1
the +'e0' comes from http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/isnumeric-isint-isnumber
this would lead to your statement
SELECT
*
FROM
Table
ORDER BY
ISNUMERIC([yourvarchar] +'e0') DESC
, LEN([yourvarchar]) ASC
the first sorting column will put numeric on top.
the second sorts by length, so 10 will preceed 0001 (which is stupid?!)
this leads to the second version:
SELECT
*
FROM
Table
ORDER BY
ISNUMERIC([yourvarchar] +'e0') DESC
, RIGHT('00000000000000000000'+[yourvarchar], 20) ASC
the second column now gets right padded with '0', so natural sorting puts integers with leading zeros (0,01,10,0100...) in correct order (correct!) - but all alphas would be enhanced with '0'-chars (performance)
so third version:
SELECT
*
FROM
Table
ORDER BY
ISNUMERIC([yourvarchar] +'e0') DESC
, CASE WHEN ISNUMERIC([yourvarchar] +'e0') = 1
THEN RIGHT('00000000000000000000' + [yourvarchar], 20) ASC
ELSE LTRIM(RTRIM([yourvarchar]))
END ASC
now numbers first get padded with '0'-chars (of course, the length 20 could be enhanced) - which sorts numbers right - and alphas only get trimmed
I solved it in a very simple way writing this in the "order" part
ORDER BY (
sr.codice +0
)
ASC
This seems to work very well, in fact I had the following sorting:
16079 Customer X
016082 Customer Y
16413 Customer Z
So the 0 in front of 16082 is considered correctly.
This seems to work:
select your_column
from your_table
order by
case when isnumeric(your_column) = 1 then your_column else 999999999 end,
your_column
This query is helpful for you. In this query, a column has data type varchar is arranged by good order.For example- In this column data are:- G1,G34,G10,G3. So, after running this query, you see the results: - G1,G10,G3,G34.
SELECT *,
(CASE WHEN ISNUMERIC(column_name) = 1 THEN 0 ELSE 1 END) IsNum
FROM table_name
ORDER BY IsNum, LEN(column_name), column_name;
This may help you, I have tried this when i got the same issue.
SELECT *
FROM tab
ORDER BY IIF(TRY_CAST(val AS INT) IS NULL, 1, 0),TRY_CAST(val AS INT);
The easiest and efficient way to get the job done is using TRY_CAST
SELECT my_column
FROM my_table
WHERE <condition>
ORDER BY TRY_CAST(my_column AS NUMERIC) DESC
This will sort all numbers in descending order and push down all non numeric values
SELECT FIELD FROM TABLE
ORDER BY
isnumeric(FIELD) desc,
CASE ISNUMERIC(test)
WHEN 1 THEN CAST(CAST(test AS MONEY) AS INT)
ELSE NULL
END,
FIELD
As per this link you need to cast to MONEY then INT to avoid ordering '$' as a number.
SELECT *,
ROW_NUMBER()OVER(ORDER BY CASE WHEN ISNUMERIC (ID)=1 THEN CONVERT(NUMERIC(20,2),SUBSTRING(Id, PATINDEX('%[0-9]%', Id), LEN(Id)))END DESC)Rn ---- numerical
FROM
(
SELECT '1'Id UNION ALL
SELECT '25.20' Id UNION ALL
SELECT 'A115' Id UNION ALL
SELECT '2541' Id UNION ALL
SELECT '571.50' Id UNION ALL
SELECT '67' Id UNION ALL
SELECT 'B48' Id UNION ALL
SELECT '500' Id UNION ALL
SELECT '147.54' Id UNION ALL
SELECT 'A-100' Id
)A
ORDER BY
CASE WHEN ISNUMERIC (ID)=0 /* alphabetical sort */
THEN CASE WHEN PATINDEX('%[0-9]%', Id)=0
THEN LEFT(Id,PATINDEX('%[0-9]%',Id))
ELSE LEFT(Id,PATINDEX('%[0-9]%',Id)-1)
END
END DESC