vfp query like command not working - sql

SELECT iif( LIKE(sol,'EM06%'), "other",sol) as solGroup;
FROM dpgift GROUP BY solGroup
The above should give me a column containing unique sol values. In addition, any sol value starting with EM06 should be grouped into "other". It doesn't work though, instead it returns the following.
Solgroup
DM081
EM061
EM081
EM100
EM101
EM105
EM111
TM081
Can anyone see what i'm doing wrong here? the 2nd and 3rd line should be called "other".
I've used this like command many times and it's never done this before. I can't see anything wrong with the syntax and I've tried other variations without success. I've even tried casting in case a certain field type doesn't work but the result is always the same.
edit: using a '*' and putting the wildcard string as the first parameter works. I've actually been making this mistake for a while in the following manner:
iif( (LIKE("4%",sol) OR sol = "4"),"8M","other");
The like does nothing here but i hadn't noticed since the '=' operator returns true if sol starts with '4' (can someone link me a reference to '=' behavior?). The reason i included the sol = "4" is because i assumed % meant one or more char rather than 0 or more.
Anyway, i've gone back and changed all my code to iif(like("wtvr*",string),stringtrue,stringfalse)
I imagine using '=' to compare strings is not recommended since it doesn't seem to be mentioned in the msdn library.

another alternative is to use "$", AT() or ATC()
"$" means if the left side is found ANYWHERE in the right side...
iif( "EM06" $ sol, "other", sol )
AT() is to compare if a string is found in another, but IS CASE-SENSITIVE, returns the character position found in the string (VFP is 1-based, not zero-based)
iif( at( "EM06", sol ) > 0, "other", sol )
or
ATC() -- same as AT(), but is NOT case-sensitive.
If you specifically want the "EM06" to be at the start of the string, you could even just do a LEFT() comparison
iif( left( sol, 4 ) = "EM06", "other", sol )
or even
iif( ATC( "EM06", sol ) = 1, "other", sol )
and yes, these are all valid within SQL-Select..

Related

SQL query problem in WHERE clause, this returns all that start with

I've written the following SQL query to return all sites having "id" equal to 2.
SELECT * FROM `sites` WHERE id = '2'
And it works well. The problem is that even if I add some characters after "2" like this :
SELECT * FROM `sites` WHERE id = '2etyupp-7852-trG78'
It returns the same results as above.
How to avoid this ? that's to say return none on the second query ?
Thanks
The reason is that you are mixing types:
where id = '2'
------^ number
-----------^ string
What is a SQL engine supposed to do? Well, the standard approach is to convert the string to a number. So this is run as:
where id = 2
What happens when the string is not a number? In most databases, you get a type conversion error. However, MySQL does implicit conversion, converting the leading digits to a number. Hence, your second string just comes 2.
From this, I hope you learn not to mix data types. Compare numbers to numbers. Compare strings to strings.

Understanding ORACLE'S BETWEEN Keyword

I was helping a co-worker debug a query that was returning weird results. We narrowed it down to a line that looked like this:
WHERE COL BETWEEN '11201' AND '111226'
The value in COL comes from a call to substring, so it's a string type value. This returns no results.
Naively, I had always assumed that BETWEEN represented >= and <= and that if you call it with strings, it would cast everything to numerical type values. That works just fine if you have something like:
WHERE COL BETWEEN '11201' AND '11226'
Which returns results in the case we are using it.
Clearly, since the second snippet returns results but the first snippet does not, my understanding is mistaken.
I cast everything to numbers and tried it again, and got the expected behavior. From this, it seems like I can conclude that when it does string comparisons, it actually doesn't cast the values - instead, it goes character by character. When it gets to the third character and sees 2 > 1 in the lower bound argument, it quits based on the following behavior from the Oracle documents:
If expr3 < expr2, then the interval is empty.
Can anyone weigh in on if this is what is truly happening beneath the hood?
Thank you!
The expression:
WHERE COL BETWEEN '11201' AND '111226'
is the same as:
WHERE COL >= '11201' AND COL <= '111226'
This returns nothing because -- as strings -- '11201' > '111226'. This uses alphabetic ordering, so this would be clearer if you used letters:
WHERE COL BETWEEN 'BBCAB' AND 'BBBCCG'
Clearly, there is nothing alphabetic between these values, because 'BBC' occurs after 'BBB'.
The moral? If you want comparisons that are intuitive, use the right types.
In the expression below
WHERE COL BETWEEN '11201' AND '111226'
You are comparing a text column COL against text. The string '11201' is lexicographically greater than the string '111226'. In other words, '11201' comes after '111226' in the dictionary, or the former is greater than the latter. This is why no results are coming back. However, if you cast COL to a number, and compare that to numbers, then the comparison might work, assuming there are matching records:
WHERE TO_NUMBER(COL) BETWEEN 11201 AND 111226

Need 8 characters form a lengthy RegKey path - Invalid length parameter passed to the LEFT or SUBSTRING

I have been working with a guy to finish off a rather ingenious means by which to extract information on packages installed by SCCM 2012 vs the built-in inventoried "Programs and Features". The last piece is extracting the PACKAGEID from registry strings that have been inventoried in the aforementioned process. Each string looks like this (the target "PACKAGEID" is identified in bold:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\ LAB00003 \ac80c725-7dc7-11e5-9bc8-000c292d4525
As stated, i am not the genius behind any of this but i wanted to understand why i am getting the following error:
Msg 537, Level 16, State 3, Line 1
Invalid length parameter passed to the LEFT or SUBSTRING function.
From the following query:
SELECT
DataType0,
KeyPath0,
Name0,
Value0,
(
SELECT SUBSTRING(KeyPath0, LEN(LEFT(KeyPath0, CHARINDEX ('\System\', KeyPath0))) + 1, LEN(KeyPath0) - LEN(LEFT(KeyPath0, CHARINDEX ('\System\', KeyPath0))) - LEN(RIGHT(KeyPath0, LEN(KeyPath0) - CHARINDEX ('\', KeyPath0))) - 1)
) as "Package ID"
FROM
dbo.v_GS_Registry_Values0
i verified that the the dbo.v_GS_Registry_Values0 view does indeed have the reg key string in it via select * from SCCM_Ext.vex_GS_Registry_Values0 but despite tons of searching, my simple sql mind cannot make sense of the query and its use of LEN & CHARINDEX.
Totally throwing myself at the mercy of this site in hopes i could get not only the resolution to this but also a better understanding of why this is happening and how the query works.
if there is ANY additional information i could provide please let me know.
If you're just trying to get the next string after \System\ you're SQL is quite complex, you can do it just with this:
SELECT left (Y.S, charindex ('\', Y.S) - 1)
from Table1
outer apply (
select CHARINDEX ('\System\', KeyPath0) as pos
) X
outer apply (
select substring (KeyPath0, X.pos + 8, 9999) as S
) Y
Example in SQL Fiddle
The first outer apply finds the \System\ the second gets the rest of the string (assuming max path is 9999 characters) and then just take the part before the next \ in the actual select.

What does LEFT in SQL do when it is not paired with JOIN and why does it cause my query to time out?

I was given the following statement:
LEFT(f.field4, CASE WHEN PATINDEX('%[^0-9]%',f.field4) = 0 THEN LEN(f.field4) ELSE PATINDEX('%[^0-9]%',f.field4) - 1 END)=#DealNumber
and am having trouble contacting the person that wrote it. Could someone explain what that statement does, and if it is valid SQL? The goal of the statement is to compare the numeric character in f.field for to the DealNumber. DNumber and DealNumber are the same except for a wildcard at the end of DealNumber.
I am trying to use it in the context of the following statement:
SELECT d.Description, d.FileID, d.DateFiled, u.Contact AS UserFiledName, d.Pages, d.Notes
FROM Documents AS d
LEFT JOIN Files AS f ON d.FileID=f.FileID
LEFT JOIN Users AS u ON d.UserFiled=u.UserID
WHERE SUBSTRING(f.Field8, 2, 1) = #LocationIDString
AND f.field4=#DNumber OR LEFT(f.field4, CASE WHEN PATINDEX('%[^0-9]%',f.field4) = 0 THEN LEN(f.field4) ELSE PATINDEX('%[^0-9]%',f.field4) - 1 END)=#DealNumber"
but my code keeps timing out when I execute it.
It's the CASE clause which is slowing things down, not LEFT per se (although LEFT may prevent the use of indexes, which will have an effect).
The CASE determines what should be compared with #DealNumber, and I think it does the following...
If f.field4 does not start with a digit, use LEFT(f.field4, LEN(f.field4))=#DealNumber: that's equivalent to f.field4=#DealNumber.
If f.field4 does start with digits, use {those digits}=#DealNumber.
This sort of computation isn't very efficient.
I would attempt the following, which makes the large assumption that a mixed string can be cast as an integer — that is, that if you convert ABC to an integer you get zero, and if you convert 123ABC you get what can be converted, 123. I can't find any documentation which says whether that is possible or not.
AND f.field4=#DNumber
OR (f.field4=#DealNumber AND integer(f.field4)=0)
OR (integer(f.field4)=#DealNumber)
The first line is the same as your AND. The second line selects f.field4=#DealNumber only if f.field4 does not start with a number. The third line selects where the initial numeric portion of f.field4 is the same as #DealNumber.
As I say, there is an assumption here that integer() will work in this way. You may need to define a CAST function to do that conversion with strings. That's rather beyond me, although I would be confident that even such a function would be faster than a CASE as you currently have.
From the doc:
left(str text, n int)
Return first n characters in the string. When n is negative, return all but last |n| characters.

SQL function Instr()

I am having a column named DP as shown:
07-APR-2011
12-APR-2011
26-APR-2011
Now to retrieve the query for selecting the payments made in the month of april i came across a query
select * from payments where instr(dp,'APR')<>0
Okay , i am well acquainted with INSTR function and > sign , but cant interpret the logic with<> sign here !
[UPDATE]
i am also aware that <> is equivalent of != .
But my point is we could have used
instr(dp,'APR') instead of doing instr(dp,'APR')<>0
<> means "is not equal to". You can also write !=, if you prefer.
instr(dp,'APR') returns zero if 'APR' is not a substring of dp, so instr(dp,'APR')<>0 means "'APR' is a substring of dp". It could also be written as dp LIKE '%APR%'.
Update for updated question:
But my point is we could have used instr(dp,'APR') instead of doing instr(dp,'APR')<>0
No, you couldn't have. Some dialects of SQL treat zero as "false" and other integers as "true", but Oracle does not do this. It treats integers and Booleans as separate types, and does not implicitly convert between them. WHERE 0 is not a valid WHERE-clause.
<> is Not Equals - basically it's checking that a substring of 'APR' appears in the string.
If that function returned 0 then it would indicate 'APR' does not appear anywhere in the string to be searched.