select where number combination matches part of integer SQL - sql

Assuming a simple one but Im looking up a customer ID ie: 930566615552 and only have the last 8 digits 66615552 - how would one do this?
I've attempted a WHERE RIGHT, LIKE and Cast the column as vachar but no avail.
I'm sure this question has been asked before, I know I'm just searching the wrong terms to find the answer!

You could query
... WHERE CAST(id AS text) LIKE '%66615552'
Indexing for such a query would require a trigram index.

there is modulus operator %
So
5 % 10 = 5
325 % 100 = 25
457322844 % 10000 = 2844
but it has caveats:
you need to specify correct base that will be dynamic in your case
it ignores index for this numeric column

A couple of options if the column is an INT and you always have the last 8 digits of the id:
SELECT * FROM customer WHERE id % 100000000 = 66615552;
SELECT * FROM customer WHERE RIGHT(CAST(id AS TEXT), 8) = '66615552';

Try with right function:
SELECT * FROM customer WHERE RIGHT(id, 8) = '66615552'
OR Use like operator
SELECT * FROM customer WHERE id, 8 like '%66615552'

Related

SQL help - count all serialNumbers except those with specific cases

I need help with writing a case statement inside of a where clause.
Let's say we have a bunch of serial numbers stored in a database.
They are prefixed with some letters to denote their group.
Here is what I need to accomplish:
Exclude all serial numbers that begin with 'GIU' unless some conditions apply:
If the serial number starts with GIU and is 15 chars long and the last 4 numbers are less than 5000, then exclude it, otherwise include it.
If the serial number starts with GIU and is 16 chars long and the last 5 numbers are less than 10000, then exclude it, otherwise include it.
ex. GIU930798246071 should be included because: begins with GIU -> 15 chars long -> 6071 > 5000.
ex2. GIU9307982410621 should be included because it begins with GIU -> 16 chars long -> 10621 > 10000.
ex3. GIU930798243071 should be excluded because 15 chars long -> last 4 digits (3071) < 5000.
If I wanted to run a query to count these results, I tried:
select count(serialNum)
FROM serialNumbers
WHERE serialNum not like (
case when LEN(serialNum) = 15 and SUBSTRING(serialNum, 1, 3) = 'GIU' and RIGHT(serialNum, 4) < 5000 then 'GIU%'
when LEN(serialNum) = 16 and SUBSTRING(serialNum, 1, 3) = 'GIU' and RIGHT(serialNum, 5) < 10000 then 'GIU%' end)
I'm trying to append the results of the case statement to the not like statement if those conditions apply.
Running the query returns null, so I know some part of the case is ruining the entire query.
Also, there are other serialNum who prefix start with other letters which it should also be counting.
I basically just need it to count all serialNums except the ones that start with GIU for these specific cases.
Any and all help is appreciated.
So, what you could do is do a column to confirm what you are looking for (or not). Once you get it confirmed, then do it. By taking a slight shift from what Bart provided, you need to explicitly INCLUDE the "GIU" as part of the condition
what DONT you want...
( left( serialNum, 3 ) = 'GIU'
AND LEN(serialNum) = 15
AND CAST(RIGHT(serialNum, 4) AS INT) < 5000 )
OR
( left( serialNum, 3 ) = 'GIU'
AND LEN(serialNum) = 16
AND CAST(RIGHT(serialNum, 5) AS INT) < 10000 )
So if the where clause was the ABOVE, you would ONLY get those in the excluded realm. So to invert this,
WHERE NOT ( above condition1 or condition2 )
thus
WHERE
NOT (
( left( serialNum, 3 ) = 'GIU'
AND LEN(serialNum) = 15
AND CAST(RIGHT(serialNum, 4) AS INT) < 5000 )
OR
( left( serialNum, 3 ) = 'GIU'
AND LEN(serialNum) = 16
AND CAST(RIGHT(serialNum, 5) AS INT) < 10000 )
)
Sometimes things might be simpler than you think. I rearranged your WHERE-clause just to match the specs you provide in the description. I get something like this.
select count(serialNum)
FROM serialNumbers
WHERE
serialNum not like 'GIU%' or
(LEN(serialNum) = 15 and CAST(RIGHT(serialNum, 4) AS INT) >= 5000) or
(LEN(serialNum) = 16 and CAST(RIGHT(serialNum, 5) AS INT) >= 10000)
Does this help?
Note that I explicitly casted the last 4 or 5 positions of the serial number to an integer. I assume the query will fail if those positions are not numeric. There are solutions for such cases as well, but for clarity I omitted them here.
Edit:
There is an alternative solution, assuming that the above query's logic is correct.
A 4-digit number larger than or equal to 5000 has the form 5nnn, 6nnn, 7nnn, 8nnn, or 9nnn. A 5-digit number larger than or equal to 10000 does not start with a 0.
Using LIKE pattern matching for those cases, you could probably use the following query as well:
select count(serialNum)
FROM serialNumbers
WHERE
serialNum not like 'GIU%' or
(LEN(serialNum) = 15 and serialNum like '%[56789]___') or
(LEN(serialNum) = 16 and serialNum like '%[^0]____')
Note that I used an underscore in the LIKE-patterns here to match any single character. I simply assume that they will actually be digits.
Edit 2:
Sorry. Re-reading your question, I probably got the last digits checking the wrong way around. Fixed it.

SQL Filter numbers between x and x and ignore strings

I have a table in SQL Server where I need to filter rooms by name and type. The problem is, that the names are stored as varchar and there are also some rooms with letters. I need to filter out the rooms with letters before I can compare them as int or otherwhise I will get an error.
Here's an example from Room.Name:
030
210a
210b
Lan-Room-A
240
I can work around the room names with a or b with LEFT(Rooms.Name, 3) but if I want to add (LEFT(Rooms.Name, 3) BETWEEN 0 and 350 and it gets to Lan-Room-A it oviously can't convert a string to int. I also need to do additional filtering like Room.Type = 6 for example.
SELECT
Room.Name,
Room.Descr,
Room.MainUser
WHERE
LEFT(Room.Name, 1) NOT LIKE '%[0-9]%'
AND LEFT(Room.Name, 3) BETWEEN 0 AND 350
AND Room.Type = 6
(Removed some joins for simplicity)
I simply need to filter out the rows which contain strings before the when clause, but I have no idea how.
Do you guys have any idea?
Please note that I can't edit the database.
Thanks in advance.
You could use TRY_CAST:
SELECT *
FROM Rooms
WHERE TRY_CAST(LEFT(Rooms.Name, 3) AS INT) BETWEEN 0 and 350;
DBFiddle Demo
Your second approach is not guaranteed to work even with correct check:
WHERE LEFT(Room.Name, 1) NOT LIKE '%[0-9]%'
AND LEFT(Room.Name, 3) BETWEEN 0 AND 350
and Room.Type = 6
Query optimizer could check conditions in any order so LEFT(Room.Name, 3) BETWEEN 0 AND 350 could yield conversion error.
I don't understand the issue. You can use strings:
WHERE Room.Name NOT LIKE '[0-9]%' AND
LEFT(Room.Name, 3) BETWEEN '0' AND '350' AND
Room.Type = 6
However, I suspect your intention is captured by:
WHERE Room.Name >= '000' AND
Room.Name < '351' AND
Room.Type = 6
This works because you have zero-padded the numbers, so string comparisons will work.
For 2008. Please use this.
Solution-
;WITH CTE AS
(
SELECT '030' a UNION ALL
SELECT '210a' UNION ALL
SELECT '210b' UNION ALL
SELECT 'Lan-Room-A' UNION ALL
SELECT '240'
)
SELECT * FROM CTE
WHERE
PATINDEX('%[0-9]%', a) = 1 AND
1 = CASE WHEN CAST(LEFT(a, 3) AS INT) BETWEEN 0 and 350 THEN 1 ELSE 0 END
OUTPUT
a
----------
030
210a
210b
240
(4 rows affected)

WHERE varchar = variable length of 0's

Table_A
ID Number
-- ------
1 0
2 00
3 0123
4 000000
5 01240
6 000
The 'Number' column is data type varchar.
EDIT for clarity.
My question is, can I easily pull back all rows of data which contain a variable length string of 0's?
I have tried:
SELECT *
FROM Table_A
WHERE LEFT(Number,1) = '0' AND RIGHT(Number,1) = '0'
Using the above, it would still return the below, using the example table provided.
ID Number
-- ------
1 0
2 00
4 000000
5 01240
6 000
I was looking for a function which I could pass the LEN(Number) int into, and then it generates a string of a specfic character (in my case a string of 0's). I wasn't able to find anything though.
Oh, and I also tried adding a SUBSTRING to the WHERE clause, but sometimes the Number column has a number which has a 0's in the middle, so it still returned strings with other numbers except only 0.
SUBSTRING(Number,ROUND(LEN(Number)/2,0),1) = '0'
Any help is appreciated.
So, you want a string that doesn't contain anything that isn't a 0? Sounds like it's time for a double-negative:
SELECT *
FROM Table_A
WHERE NOT Number like '%[^0]%'
AND number like '0%' --But we do want it to contain at least one zero
(The final check is so that we don't match the empty string)
Answer:
Where number like '%0%'
Your can use this query :
SELECT * FROM Table_A WHERE Number LIKE '%0%';
It'll solve your problem.
SELECT *
FROM yourtable
WHERE len(Number) - len(replace(number,'0','')) >= 0
One more approach
You can use this following one also,you will get your expected result.
SELECT *
FROM Table_A
WHERE Nunber not like '%[1-9]%'
Thanks.

Cannot figure out how to use MODULO/MODULUS function in Caché SQL

Here is the documentation.
I'm using DB Visualizer Pro 9.2.6
I've tried multiple variants including the following
SELECT TOP 10 * FROM tableName WHERE {ID MOD(5,3)}
SELECT TOP 10 * FROM tableName WHERE ID MOD(5,3)
SELECT TOP 10 * FROM tableName WHERE ID MOD 5 = 3
SELECT TOP 10 * FROM tableName WHERE ID % 5 = 3
In all honesty the documentation makes no sense to me anyway... Is "fn" field name? I assume it's a function but then what field are they selecting? It's just confusing...
It appears from the examples that fn should be included, within the curly brackets:
The following example shows the remainder returned by MOD.
SELECT DISTINCT {fn MOD(5,3)} AS Remainder
FROM Sample.Person
returns 2
The following example shows the remainder returned by MOD with a negative dividend.
SELECT DISTINCT {fn MOD(-5,3)} AS Remainder
FROM Sample.Person
returns 1
If you check out another function, like ROUND they use the same syntax (among others).
So in your case, maybe something like (assuming you want records satisfying 5 % ID == 3)
SELECT TOP 10 * FROM tableName WHERE {fn MOD(ID,5)} = 3
Confusing? Yes.
There is also a binary operator for modulo: #
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_langelements#GSQL_langelements_ops_math

Finding even or odd ID values

I was working on a query today which required me to use the following to find all odd number ID values
(ID % 2) <> 0
Can anyone tell me what this is doing? It worked, which is great, but I'd like to know why.
ID % 2 is checking what the remainder is if you divide ID by 2. If you divide an even number by 2 it will always have a remainder of 0. Any other number (odd) will result in a non-zero value. Which is what is checking for.
For finding the even number we should use
select num from table where ( num % 2 ) = 0
As Below Doc specify
dividend % divisor
Returns the remainder of one number divided by another.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/modulo-transact-sql#syntax
For Example
13 % 2 return 1
Next part is <> which denotes Not equals.
Therefor what your statement mean is
Remainder of ID when it divided by 2 not equals to 0
Be careful because this is not going to work in Oracle database. Same Expression will be like below.
MOD(ID, 2) <> 0
ID % 2 reduces all integer (monetary and numeric are allowed, too) numbers to 0 and 1 effectively.
Read about the modulo operator in the manual.
In oracle,
select num from table where MOD (num, 2) = 0;
dividend % divisor
Dividend is the numeric expression to divide. Dividend must be any expression of integer data type in sql server.
Divisor is the numeric expression to divide the dividend. Divisor must be expression of integer data type except in sql server.
SELECT 15 % 2
Output
1
Dividend = 15
Divisor = 2
Let's say you wanted to query
Query a list of CITY names from STATION with even ID numbers only.
Schema structure for STATION:
ID Number
CITY varchar
STATE varchar
select CITY from STATION as st where st.id % 2 = 0
Will fetch the even set of records
In order to fetch the odd records with Id as odd number.
select CITY from STATION as st where st.id % 2 <> 0
% function reduces the value to either 0 or 1
It's taking the ID , dividing it by 2 and checking if the remainder is not zero; meaning, it's an odd ID.
<> means not equal. however, in some versions of SQL, you can write !=