Microsoft SQL between statement for characters is not inclusive? - sql

I am trying to select all values that have a first name beginning with the letters a-d, however when I do this
select * from tblprofile where firstname between 'a' and 'd'
I get all values from a to c, not including d, how can I make sure it includes d?

It is inclusive.
You don't get the results you want because any string beginning with 'd' and longer than 1 character is greater than 'd'. For example 'da' > 'd'.
So, your query would return all values starting with 'a', 'b', 'c', and a value 'd'.
To get the results you want use
select * from tblprofile where firstname >= 'a' and firstname < 'e'

Try using Left() Function:
SELECT *
FROM tblprofile
WHERE LEFT(FirstName,1) between 'a' and 'd'

Another way is using a union select like this
SELECT * FROM tblprofile WHERE LEFT(FirstName,1) = 'a'
union
SELECT * FROM tblprofile WHERE LEFT(FirstName,1) = 'b'
union
SELECT * FROM tblprofile WHERE LEFT(FirstName,1) = 'c'
union
SELECT * FROM tblprofile WHERE LEFT(FirstName,1) = 'z'
The advantage of using union is if you need to get the results stating with A, K and X, strings out of sequence.

Related

Oracle SQL elegant way of decoding regexp

I have the below table:
MATERIAL
ESMART_1ELE_ADE
ELEC_SMETS1_CREDIT
ESMART_1ELE_ALCS
GAS-METER-PREPAY
ELEC_SMETS1
What would be the most elegant way of obtaining a column which, if the row contains either the string 'SMART' or 'SMETS', outputs 'S' else 'D'?
MATERIAL
EXPECTED_OUTPUT
ESMART_1ELE_ADE
S
ELEC_SMETS1_CREDIT
S
ESMART_1ELE_ALCS
S
GAS-METER-PREPAY
D
ELEC_SMETS1
S
Code to get the first table:
WITH aux ( material ) AS (
SELECT
'ESMART_1ELE_ADE'
FROM
dual
UNION ALL
SELECT
'ELEC_SMETS1_CREDIT'
FROM
dual
UNION ALL
SELECT
'ESMART_1ELE_ALCS'
FROM
dual
UNION ALL
SELECT
'GAS-METER-PREPAY'
FROM
dual
UNION ALL
SELECT
'ELEC_SMETS1'
FROM
dual
)
SELECT
*
FROM
aux
'SMART' or 'SMETS', outputs 'S' else 'D'?
I would use like:
select a.*,
(case when material like '%SMART%' or material like '%SMETS%'
then 'S' else 'D'
end)
from aux a;
However, regexp_like() is more concise:
select a.*,
(case when regexp_like(material, 'SMART|SMETS')
then 'S' else 'D'
end)
from aux a;

SQL Server - Suggest a query for this scenario

In SQL Server, "I have a field (D1) as 101, 102, 103 in database table: mastersupport.
I have this query
select right(D1, R)
from mastersupport.
It will return results like 1, 2, 3
But my requirement is that I want to show result as A, B, C only instead of 1,2,3". Please suggest a query.
I tried with the below but got syntax error.
SELECT DISTINCT
REPLACE(REPLACE((RIGHT(D1, 1)), '1' , ‘A’), '2', ‘B’, ) AS ExtractString
FROM
master_support;
Any other query to derive the result as A, B, C ......
You can use a case expression:
select case right(d1, 1)
when '1' then 'A'
when '2' then 'B'
when '3' then 'C'
...
end as extract_string
from master_support
Note that if d1 is of a numeric datatype, using arithmetics seems like a more natural approach:
select case d1 % 10
when 1 then 'A'
when 2 then 'B'
when 3 then 'C'
...
end extract_string
from master_support

Comparing 2 lists in Oracle

I have 2 lists which I need to compare. I need to find if at least one element from List A is found in List B. I know IN doesn't work with 2 lists. What are my other options?
Basically something like this :
SELECT
CASE WHEN ('A','B','C') IN ('A','Z','H') THEN 1 ELSE 0 END "FOUND"
FROM DUAL
Would appreciate any help!
You are probably looking for something like this. The WITH clause is there just to simulate your "lists" (whatever you mean by that); they are not really part of the solution. The query you need is just the last three lines (plus the semicolon at the end).
with
first_list (str) as (
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual
),
second_list(str) as (
select 'A' from dual union all
select 'Z' from dual union all
select 'H' from dual
)
select case when exists (select * from first_list f join second_list s
on f.str = s.str) then 1 else 0 end as found
from dual
;
FOUND
----------
1
In Oracle you can do:
select
count(*) as total_matches
from table(sys.ODCIVarchar2List('A', 'B', 'C')) x,
table(sys.ODCIVarchar2List('A', 'Z', 'H')) y
where x.column_value = y.column_value;
You need to repeat the conditions:
SELECT (CASE WHEN 'A' IN ('A', 'Z', 'H') OR
'B' IN ('A', 'Z', 'H') OR
'C' IN ('A', 'Z', 'H')
THEN 1 ELSE 0
END) as "FOUND"
FROM DUAL
If you are working with collection of String you can try Multiset Operators.
create type coll_of_varchar2 is table of varchar2(4000);
and:
-- check if exits
select * from dual where cardinality (coll_of_varchar2('A','B','C') multiset intersect coll_of_varchar2('A','Z','H')) > 0;
-- list of maching elments
select * from table(coll_of_varchar2('A','B','C') multiset intersect coll_of_varchar2('A','Z','H'));
Additionally:
-- union of elemtns
select * from table(coll_of_varchar2('A','B','C') multiset union distinct coll_of_varchar2('A','Z','H'));
select * from table(coll_of_varchar2('A','B','C') multiset union all coll_of_varchar2('A','Z','H'));
-- eelemnt from col1 not in col2
select * from table(coll_of_varchar2('A','A','B','C') multiset except all coll_of_varchar2('A','Z','H'));
select * from table(coll_of_varchar2('A','A','B','C') multiset except distinct coll_of_varchar2('A','Z','H'));
-- check if col1 is subset col2
select * from dual where coll_of_varchar2('B','A') submultiset coll_of_varchar2('A','Z','H','B');
I am trying to do something very similar but the first list is another field on the same query created with listagg and containing integer numbers like:
LISTAGG(my_first_list,', ') WITHIN GROUP(
ORDER BY
my_id
) my_first_list
and return this with all the other fields that I am already returning
SELECT
CASE WHEN my_first_list IN ('1,2,3') THEN 1 ELSE 0 END "FOUND"
FROM DUAL

Select a table based on input condition

I am using oracle 10g and i need to write a query where in the table that is to be considered for producing the output is based on the user input.
i have written in the following manner, but getting an error.
UNDEFINE CDR
SELECT F.EMPLOYEE_ID FROM
( SELECT DECODE(&&CDR,25,'TABLE 1' ,22,'TABLE 2' ,19,'TABLE 3' ,16,'TABLE 4') FROM DUAL ) F
WHERE F.FLAG='G';
The closest that you can come without dynamic SQL is:
select EMPLOYEE_ID
from table1
where flag = 'G' and &&CDR = 25
union all
select EMPLOYEE_ID
from table2
where flag = 'G' and &&CDR = 19
union all
select EMPLOYEE_ID
from table4
where flag = 'G' and &&CDR = 16
union all
select EMPLOYEE_ID
from table1
where flag = 'G' and &&CDR not in (25, 19, 16)

SQL Server - Count characters between two characters

How would one count the number of letters (alphabetically a to z or z to a) between two characters?
For example:
WITH ExampleData
AS ( SELECT 'a' AS StartChar, 'e' AS EndChar
UNION ALL
SELECT 'm', 'r'
UNION ALL
SELECT 'f', 'a'
)
SELECT StartChar ,
EndChar
FROM ExampleData
Would need to produce:
StartChar EndChar Diff
a e 4
m r 5
f a -5
I see how this could easily be done using udf's and a while loop but I was wondering if there was a faster way?
SELECT StartChar, EndChar, ASCII(EndChar) - ASCII(StartChar) AS Diff
FROM ExampleData
SQL Fiddle example
assuming you've already done validity checks on StartChar and EndChar...
SELECT ASCII(EndChar) - ASCII(StartChar) as Diff
This should get the job done for you:
WITH ExampleData
AS ( SELECT 'a' AS StartChar, 'e' AS EndChar
UNION ALL
SELECT 'm', 'r'
UNION ALL
SELECT 'f', 'a'
)
SELECT StartChar ,
EndChar, ascii(EndChar) - ascii(StartChar) as Diff
FROM ExampleData
CTE is just awesome! This way you can do that if you won't want to use ASCII:
; With CharCodes (
Code
) As (
Select 65
Union All
Select Code
+ 1
From CharCodes
Where Code < 90
)
Select Second.Code
- First.Code
From CharCodes As First
, CharCodes As Second
Where First.Code = Convert(Int, Convert(VarBinary, 'A'))
And Second.Code = Convert(Int, Convert(VarBinary, 'E'))
And using the ASCII function you can do it this way:
Select ASCII('E')
- ASCII('A')