Select part of word from query? - sql

In Access, I have a field like this:
From the start until end at 01/05/2013, the XXXXXXX device was used.
I'm looking for a query that can extract the device name (in this case XXXXXXX). I was able to use mid() to get it somewhat working, but the sentence could be longer or shorter. What are some other ways to do this? Is there a find() I can use to find the location of "device"?
My SQL looks like:
SELECT Mid(Note, 68, 30)
FROM My_Log
WHERE Note LIKE "*, the*"
;

If the device name is the word before "device", and you want to find that word using only functions supported directly by the Access db engine, Mid(), InStr(), and InstrRev() can get the job done ... but it won't be pretty.
Here is an Immediate window session ...
Note = "From the start until end at 01/05/2013, the XXXXXXX device was used."
? Mid(Note, _
InstrRev(Note, " ", InStr(1, Note, " device") -1) +1, _
InStr(1, Note, " device") - InstrRev(Note, " ", InStr(1, Note, " device") -1) -1)
XXXXXXX
So you would then need to use that complex Mid() expression in a query.
However, if you can use a user-defined function in your query, the logic could be easier to manage.
Public Function FindDevice(ByVal pInput As String) As Variant
Dim astrWords() As String
Dim i As Long
Dim lngUBound As Long
Dim varReturn As Variant
varReturn = Null
astrWords = Split(pInput, " ")
lngUBound = UBound(astrWords)
For i = 0 To lngUBound
If astrWords(i) = "device" Then
varReturn = astrWords(i - 1)
Exit For
End If
Next i
FindDevice = varReturn
End Function
Then the query could be ...
SELECT FindDevice(Note) AS device_name
FROM My_Log
WHERE Note LIKE "*, the*"

If you know the name of the device, you can use Instr:
... WHERE Instr([Note], "Mydevice")>0
You can also use a table that lists devices:
SELECT Note FROM MyTable, ListTable
WHERE Note Like "*" & ListTable.Devices & "*"
Re comment:
SELECT Note
FROM MyTable
WHERE [Note] Like "*" & [enter device] & "*"
If you need to know where in notes you will find device
SELECT Note, InStr([Note],[enter device]) ...

In addition to my comments this is Oracle query that may help you. Replace dual with with your table name and query should probably work. As I mentioned all functions I'm using in this query are ANSI SQL standard. The syntax you can fix yourself. You may run all queries separately to get start, end positions and lenght of your machine name, etc...:
SELECT SUBSTR(str, start_pos, end_pos) machine_name
FROM
(
SELECT str, INSTR(str,'XXXXXXX') start_pos, Length('XXXXXXX') end_pos
FROM
(
SELECT 'From the start until end at 01/05/2013, the XXXXXXX device was used.' str FROM dual
)
)
/
SQL>
MACHINE
-------
XXXXXXX
More generic approach with the same result - eliminating Length:
SELECT SUBSTR(str_starts, 1, end_pos) machine_name FROM -- Final string
(
SELECT str_starts, INSTR(str_starts, ' ')-1 end_pos FROM -- end pos = last X pos in string starts - in 'XXXXXXX'
(
SELECT SUBSTR(str, start_pos) str_starts FROM -- strig starts from first X
(
SELECT str, INSTR(str,'XXXXXXX') start_pos FROM -- start_pos
(
SELECT 'From the start until end at 01/05/2013, the XXXXXXX device was used.' str FROM dual
))))
/

Related

How to check if string ends in date and strip result? - SQL

I'm trying to check whether or not a string ends in a year.
Input:
file_paths
wowefnowinf/wefionwe/wefowoi/2012-02-03
weofnweofn/weoew/2022-03-04
ewpfowe/ewopfew
Desired Output:
wowefnowinf/wefionwe/wefowoi/
weofnweofn/weoew/
ewpfowe/ewopfew
I'm having trouble first detecting that the strings themselves end in a date-format. This is my query:
SELECT CASE WHEN 'wowefnowinf/wefionwe/wefowoi/2012-02-03' LIKE '%/####\-##\-##'
THEN TRUE
ELSE FALSE END AS result
FROM my_table;
I should be getting true for this, but my query returns false. Any help would be appreciated.
In Snowflake you can make use of regexp_like and split_part:
with dummy as (
select 'wowefnowinf/wefionwe/wefowoi/2012-02-03' as file_path
union all
select 'weofnweofn/weoew/2022-03-04'
union all
select 'ewpfowe/ewopfew'
)
select
file_path,
split_part(file_path, '/', -1) as splitted_file_path,
regexp_like(splitted_file_path, '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]') as ends_with_date,
iff(ends_with_date, trim(file_path, splitted_file_path), file_path) as trimmed_file_path
from dummy;
Output:

embedded IIF States in SSRS

Thank you for taking your time to help me today. I am trying to use multiple if statements to control what value is displayed depending on whether each statement is true. So right now I have this below which is essentially:
IIF(expression = NULL
, CompanyAddress
, IIF(Expression='TX'
, IIF(BOOL=TRUE
,CompanyAddress
, SWITCH(DEALER ADDRESSES))
,CompanyAddress)
)
I have tested each individual IIF statements separately and I get the outcomes which I expect. Currently in the first IIF statement and the Expression = NULL is TRUE , It just outputs #Error and not the "Nothin" OR in my real case Company Address. But if Expression = NULL is FAlSE, I do get the correct output of either the companyAddress or the Dealer.
=IIF(IsNothing(Fields!CoOppId.Value)
,("nothin")
, (IIF(Fields!Addr1.Value.Contains("TX")
, IIF(Fields!UDFCustProv.Value = 1
, Fields!Addr0.Value
, Switch(
Fields!UDFMake.Value.Contains("Chevy")
, "Knapp Chevrolet" + chr(10) + "PO box " + chr(10) + "Houston TX 77210"
, Fields!UDFMake.Value.contains("Ford")
, "Sterling McCall Ford" + chr(10) + "6445 Southwest Freeway" + chr(10) + "Houston TX 77074"
, Fields!UDFMake.Value.contains("International")
, "Pliler International" + chr(10) + "2016 S. Eastman Rd" + chr(10) + "Longview TX 75602"
, Fields!UDFMake.Value.contains("Freightliner")
, "Houston Freightliner, Inc" + chr(10) +"9550 North Loop East" + chr(10) + "Houston TX 77029"
, Fields!UDFMake.Value.contains("RAM")
, "Max Haik Dodge Chrysler Jeep" +chr(10)+ "11000 I-45 North Freeway" + chr(10) + "Houston TX 77037")),Fields!Addr0.Value)))
I agree with #Daniel, the error is most likely being produce by the Fields!UDFMake.Value.Contains when the value is null, as IIF does not short-circuit.
Alternatively to the good options that #Daniel mentioned you can replace the contains method by the function InStr as:
... , Switch(
InStr(Fields!UDFMake.Value,"Chevy") > 0
, "Knapp Chevrolet" + chr(10) + "PO box " + chr(10) + "Houston TX 77210" ...
this will not produce an error even when the value of the field is Null.
I'm going to take a guess that when your CoOppId value is NULL, that your other fields in that row are also NULL. Because IIF does not utilize short circuit logic (it always evaluates both sides of the IIF), you are trying to evaluate the expression "NULL.Contains("TX")" and that will generate an #ERROR because NULL is not a string and cannot be operated on with the CONTAINS function.
There are two workarounds available for this scenario, neither of them particularly nice in my opinion, however:
1) Use nested IIFs to ensure that nothing is ever invalid.
IIF(expression is NULL
, CompanyAddress
, IIF(**IIF(expression is NULL, "", expression)** ='TX'
, IIF(BOOL=TRUE
,CompanyAddress
, SWITCH(DEALER ADDRESSES))
,CompanyAddress)
)
Look at the pseudo code above and notice the additional nested IIF around the expression that is using the CONTAINS functionality. If CoOppId doesn't exist, it substitutes in an empty string for the CONTAINS check. Even though this branch never shows it's value for the null scenario, it will at least be valid now.
2) Create a code-behind function that actually does perform short circuit logic for you:
Public Function CheckForNull(ByVal CoOppId As String, ByVal Addr1 as String, ByVal UDFMake As String, ... all fields)
If String.IsNullOrEmpty(CoOppId)
Return "Nothing"
Else
Return *** do your calculation with your fields here
End If
End Function
Which you utilize in your report like:
=Code.CheckForNull(values....)
I just roughly laid out how such a code behind function works, it's obviously not complete but should be enough to point you in the right direction.

MS Access SQL query for IP address range

IP addresses are being stored as text values in an Access database in the format 192.168.0.1 - 192.168.0.254 in a junction table.
Junction table e.g Areas
Name IPAddress
Area1 192.168.0.1 - 192.168.0.254
Area2 192.168.1.1 - 192.168.1.254
I need to be able to search for records that between these ranges e.g.
SELECT * FROM devices WHERE ipaddress = 192.168.0.1 /Returns record Name1
or
SELECT * FROM tablename WHERE ipaddress BETWEEN 192.168.0.1 AND 192.168.0.25 /Returns record Name1,Name2,Name3,etc
A successful approach would be composed of three parts:
Parse the IPAddress column and split it up into two logical (text) columns: IPAddressLow and IPAddressHigh that capture the range of IPs for an area. Let's call this qryAreas:
select
[Name]
, ... as IPAddressLow
, ... as IPAddressHigh
from Areas
Implement a function (in VBA which you can then call from within Access SQL) to do comparisons on IP addresses. The comparator function could be something like:
' Returns:
' -1 if IP1 < IP2
' 0 if IP1 = IP2
' 1 if IP1 > IP2
Function CompareIPAddresses(ip1 As String, ip2 As String) As Integer
ip1_arr = Split(ip1, ".")
ip2_arr = Split(ip2, ".")
For i = 0 To 3
ip1_arr(i) = CLng(ip1_arr(i))
ip2_arr(i) = CLng(ip2_arr(i))
Next i
If ip1 = ip2 Then
retval = 0
ElseIf ip1_arr(0) < ip2_arr(0) Then
retval = -1
ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) < ip2_arr(1) Then
retval = -1
ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) = ip2_arr(1) And ip1_arr(2) < ip2_arr(2) Then
retval = -1
ElseIf ip1_arr(0) = ip2_arr(0) And ip1_arr(1) = ip2_arr(1) And ip1_arr(2) = ip2_arr(2) And ip1_arr(3) < ip2_arr(3) Then
retval = -1
Else
retval = 1
End If
CompareIPAddresses = retval
End Function
Use the above function in queries to figure out if an IP address is equal to a certain value or falls within a certain range. E.g., if you have an address 192.168.1.100 and want to find out which area it's in, you can do:
select [Name]
from qryAreas
where CompareIPAddresses(IPAddressLow, '192.168.1.100') in (-1, 0)
and CompareIPAddresses('192.168.1.100', IPAddressHigh) in (-1, 0)
The where clause here is the clunkier equivalent of the more elegant where 192.168.1.100 between IPAddressLow and IPAddressHigh syntax, because you don't have a native IP address data type and its corresponding operators--so you're rolling your own.
For searching on a range of IP addresses you might be able to use a little VBA function like this
Option Compare Database
Option Explicit
Public Function ZeroPaddedIP(IP As String) As String
Dim rtn As String, octets() As String, octet As Variant
rtn = ""
octets = Split(IP, ".")
For Each octet In octets
rtn = rtn & "." & Format(Val(octet), "000")
Next
ZeroPaddedIP = Mid(rtn, 2) ' trim leading "."
End Function
It pads the octets with leading zeros so
ZeroPaddedIP("192.168.0.1") --> "192.168.000.001"
and your query could do something like
SELECT * FROM tablename
WHERE ZeroPaddedIP(ipaddress) BETWEEN "192.168.000.001" AND "192.168.000.025"
That query will do a table scan because it cannot use any existing index on [ipaddress]. If performance is an issue, you might consider storing your IP addresses in padded form (either instead of, or in addition to the normal un-padded format).
Edit
For a test table named [NetworkData] ...
ID IP Description
-- ------------- -----------
1 192.168.0.1 router
2 192.168.0.2 test server
3 192.168.0.3 dev server
4 192.168.0.102 test client
5 192.168.0.103 dev client
... the VBA function shown above could be used in an Access query like this ...
SELECT
IP,
ZeroPaddedIP(IP) AS PaddedIP
FROM NetworkData
... to produce the following results ...
IP PaddedIP
------------- ---------------
192.168.0.1 192.168.000.001
192.168.0.2 192.168.000.002
192.168.0.3 192.168.000.003
192.168.0.102 192.168.000.102
192.168.0.103 192.168.000.103
... but only if the query is executed from within Access itself. The same results could be obtained from the following query, but this one will work if the query is run against the Access database from some other application (like Excel):
SELECT
IP,
Right('000' & Octet1, 3) & '.' & Right('000' & Octet2, 3) & '.' & Right('000' & Octet3, 3) & '.' & Right('000' & Octet4, 3) AS PaddedIP
FROM
(
SELECT
IP,
Octet1,
Octet2,
Left(TheRest2, InStr(TheRest2, '.') - 1) AS Octet3,
Mid(TheRest2, InStr(TheRest2, '.') + 1) AS Octet4
FROM
(
SELECT
IP,
Octet1,
Left(TheRest1, InStr(TheRest1, '.') - 1) AS Octet2,
Mid(TheRest1, InStr(TheRest1, '.') + 1) AS theRest2
FROM
(
SELECT
IP,
Left(IP, InStr(IP, '.') - 1) AS Octet1,
Mid(IP, InStr(IP, '.') + 1) AS theRest1
FROM NetworkData
) AS q1
) AS q2
) AS q3
So, if you were querying the data from Excel (or wherever) and you tried to use
SELECT * FROM NetworkData
WHERE IP Between '192.168.0.1' And '192.168.0.25'
you would get the following incorrect result
ID IP Description
-- ------------- -----------
1 192.168.0.1 router
2 192.168.0.2 test server
4 192.168.0.102 test client
5 192.168.0.103 dev client
whereas if you used
SELECT NetworkData.*
FROM
NetworkData
INNER JOIN
(
SELECT
IP,
Right('000' & Octet1, 3) & '.' & Right('000' & Octet2, 3) & '.' & Right('000' & Octet3, 3) & '.' & Right('000' & Octet4, 3) AS PaddedIP
FROM
(
SELECT
IP,
Octet1,
Octet2,
Left(TheRest2, InStr(TheRest2, '.') - 1) AS Octet3,
Mid(TheRest2, InStr(TheRest2, '.') + 1) AS Octet4
FROM
(
SELECT
IP,
Octet1,
Left(TheRest1, InStr(TheRest1, '.') - 1) AS Octet2,
Mid(TheRest1, InStr(TheRest1, '.') + 1) AS theRest2
FROM
(
SELECT
IP,
Left(IP, InStr(IP, '.') - 1) AS Octet1,
Mid(IP, InStr(IP, '.') + 1) AS theRest1
FROM NetworkData
) AS q1
) AS q2
) AS q3
) AS q4
ON q4.IP = NetworkData.IP
WHERE q4.PaddedIP Between '192.168.000.001' And '192.168.000.025'
you would receive the following correct result
ID IP Description
-- ----------- -----------
1 192.168.0.1 router
2 192.168.0.2 test server
3 192.168.0.3 dev server

How to match numbers that are present between ] and [?

How do I match numbers that are present between ] and [ (not [ and ])?
EDIT-1
In other words, I want to extract those rows where I have a number between ] and [.
My table looks like this...
ID1 id mycolmn
1 100 [ab-ee]43[ddhj]
2 233 [aa-33]49[kl-00]
3 344 [ss-23][wdsd]
And I should get
43
49
EDIT-1 ends
See example file here. I have a column in MyDatabase and I want to extract those rows where there are two digit numbers between ] and [.
Example [ab-ee]43[ddhj] or [aa-33]49[kl-00]
The following did not work.
SELECT * from myTable where [mycolmn] Like "*\]##\[*"
You can use VBA or SQL.
VBA:
Function GetCode(MyColumn As String) As String
Dim RE As New RegExp
Dim colMatches As MatchCollection
With RE
.Pattern = "\]\d\d\["
.IgnoreCase = True
.Global = False
.Multiline = False
Set colMatches = .Execute(MyColumn)
End With
If colMatches.Count > 0 Then
GetCode = Replace(Replace(colMatches(0).Value, "[", ""), "]", "")
Else
GetCode = ""
End If
End Function
And you would call it like this:
SELECT GetCode([test]) AS MyDigits
FROM test;
If you want a strait SQL solution:
SELECT Mid([test],InStr([test],"]")+1,2) AS MyDigits
FROM test;
This assumes that your numbers come after the first ]. If not, it can be modified with more IIF, INSTR, & MID functions to match your pattern. It would be ugly, but it can work.
Yo dawg I heard you like brackets so I put brackets in your brackets so you can escape your brackets
Select * FROM yourTable WHERE MAtch LIKE "*]##[ [ ]*"
Select Mid([MyColumn],InStr([MyColumn],"]")+1,2) AS MyDigits
FROM yourTable WHERE [MyColumn] LIKE "*]##[ [ ]*"
Please award the check if this answer suits your needs. That's how StackOverflow works.
You can try PATINDEX:
create table TestPatIndex
(
MyData varchar(100)
)
insert into TestPatIndex select '[ab-ee]43[ddhj]'
insert into TestPatIndex select '[ab-ee]XX[ddhj]'
select SUBSTRING(MyData, PATINDEX ('%][0-9][0-9][[]%', MyData ) + 1, 2)
from TestPatIndex
where isnumeric(SUBSTRING(MyData, PATINDEX ('%][0-9][0-9][[]%', MyData ) + 1, 2)) = 1
Here is a link to SQL fiddle.
Something like this should work in MS Access:
SELECT MyData AS Expr1
FROM TestPatIndex
where MyData like '*][0-9][0-9][[]*'

Return all results of substring with in string

I have some odd data in a vendor database but need to be able to extract multiple different parameters from one field in the db.
So from this example i would like to pull out all items that fall between (" % ")
Between quotes is a string, disregard that it looks like code:
"Func_GetParameterLatestValue("IBW Patient Height RT Assess") kHeight =Func_GetParameterLatestValue("Height For IBW Vent Misc") If (kSex) = "" Then
Return_Value =NULL Else If kHeight > 0 Then If kSex=1 Then Return_Value= Round(((kHeight - 152.4)*.91)+50,0) Else
Return_Value= Round(((kHeight - 152.4)*.91)+45.5,0) End IF Else Return_Value = NULL End IF End IF ' Return_Value = kHeight '("IBW Patient Height RT Assess")"
so the return values would be:
IBW Patient Height RT Assess,
Height For IBW Vent Misc,
IBW Patient Height RT Assess
Im open to any suggestions to try and make this work. Ideally i would like to be able to slam the results in a subquery as well to make sure that they exist on another table.
This query currently returns the first instance
select vbs.Name,
SUBSTRING(sd.FormulaDetails,
CHARINDEX('("', sd.FormulaDetails)+2,(CHARINDEX('")',sd.FormulaDetails) - CHARINDEX('("', sd.FormulaDetails))-2)
from StatementDefinitions sd, MvVBScript vbs
where sd.ScriptID = vbs.ID
You can do this recursively with a WITH statement. Here's a shot at it. Change varchar(max) to whatever the data type of your FormulaDetails column is. In case you want it, this query returns the ScriptID and numbers the position of the chunk it finds (so 'Height For IBW Vent Misc' would be occurrence 2)
with Chunks(id,occurrence,position,token,remainder) as (
select
ScriptID,
cast(0 as int),
charindex(#token,FormulaDetails),
cast('' as varchar(max)),
substring(c,charindex(#token,FormulaDetails)+1,len(FormulaDetails))
from StatementDefinitions
where FormulaDetails like '%'+#token+'%'
union all
select
id,
occurrence+1,
charindex(#token,remainder)+position,
cast(substring(remainder,1,charindex(#token,remainder)-1) as varchar(max)),
substring(remainder,charindex(#token,remainder)+1,len(remainder))
from Chunks
where remainder like '%'+#token+'%'
)
select id, occurrence, token from Chunks
where occurrence > 0
order by id;