Index of substring in SQLite3? - string

What's the most straightforward way of finidng the index of a substring in a varchar column? charindex doesn't exist in the stock version of SQLite3 -- which is still a little surprising to me.
Specifically, I have a column with values like 010000, 011000, 010110, etc. I want to find the index of the first occurence of 11. For the examples I gave, I would expect something like NULL (or -1), 1, and 3.
I have a hacked together idea that uses length and ltrim, but it seems like a lot of work for something I need to do several times.

This is now possible using the builtin instr function.
sqlite> select instr(010000,11);
0
sqlite> select instr(011000,11);
1
sqlite> select instr(010110,11);
3

Unfortunately, I think you've found the only answer that currently works. SQLite does not have a charindex equivalent function. You an make your own with length and trim, but nothing is built in:(

Related

How to search values in excel and assigned a particular value based on logic (Based on RIGHT, IF, OR condition)

Trying to extract the values from the right side (single digit) of the ID column and based on that assigning "A","B","C",""
I have tried with the below logic, but not getting the expected result. Can anyone suggest me in this?
=IF(RIGHT(A2,1)=OR(1,2,6),"A",IF(OR(3,7,9),"B",IF(OR(4,8,0),"C",IF(5,"D",""))))
Excel Table:
ID Value
AB1ZX0 C
BC5SD2 A
FR3WDX
CA4EG7 B
There are a couple issues with your original try:
Since the cells are text based, you need quotes around the number you are testing (...="1" instead of ...=1).
You need to reference what you are testing (the RIGHT(A2,1)) each time you use IF.
You can not use OR like that; it's return is boolean so you would need to do something like =IF(OR(RIGHT(A2,1)="1", RIGHT(A2,1)="2", RIGHT(A2,1)="6"), "A", ... to make it work.
Instead, the below should do the trick, though it is a little messy and verbose:
=CONCAT(IF(RIGHT(A5,1)={"1","2","6"}, "A",
IF(RIGHT(A5,1)={"3","7","9"}, "B",
IF(RIGHT(A5,1)={"4","8","0"}, "C",
IF(RIGHT(A5,1)="5", "D","")))))
You could use a SWITCH to make a clean formula. But as already noted, the last character in ID is text and needs to be compared to text, not numbers. Here is the SWITCH based solution:
=SWITCH(RIGHT(A2,1),
"1","A","2","A","6","A",
"3","B","7","B","9","B",
"4","C","8","C","0","C",
"5","D",
"")

MATCH function not working on Table headers for some reason

I am getting n N/A error when I am searching for a specific day in the header row. If you look to the right you can see the formula where I have searched for the position of 5 using MATCH and it works.
I have tried the following variations as well
MATCH(F7,Table2[[#Headers],[1]:[60]],-1)
MATCH(F7,Table2[[#Headers],[1]:[60]],1)
But these do not work.
On the right you can see that I have created a simple range of numbers from 1 to 9 and I have searched for the number 5 in it, it is working.
PS: I know I can just use the number "23" without using MATCH. But that is not the point, the column orders may be jumbled in some cases (product ID for example). The MATCH function shouldn't fail there.
Being used as table-headers the days are not treated as numbers. Thus, you need to convert the expression you would like to match into text using TEXT() like this
=MATCH(TEXT(F7;"0"); Table2[#Headers]; 0)
Hope this helps.
I would try =index(area or table, 1 this is the row, match( field to match, area to search, 0 = exact match))
Example source here https://exceljet.net/lessons/how-to-use-index-and-match-with-a-table
Hope this helps.

Excel: Multiple Substitute without nesting and without VBA

I have cells that have data that I want to remove. The cells typically look like this:
alm1 105430_65042M
1993_5689IB
ALM99 3455 344C
0001_4555Alm5
Some but not all of the cells contain text like "almj" where "j" is a positive integer. I want to remove that part. I want the output to look like this:
105430_65042M
1993_5689IB
3455 344C
0001_4555
So something like this works
SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2,"alm1",""),"ALM99",""),"Alm5","")
But for my full data set I would need this to be several-hundred-deep nested function because my "alm" is sometimes in capital letters and sometimes not and the integer can vary from 1 to 100. This seems like a painful way to do this.
Is there a way that I can tell it to look for text listed in a column (so I can have a column in a different sheet that just goes from alm, alm1, ..., alm100 ) and then also ask it to ignore capitalization and then just replace stuff?
I tried referencing a column $M$1:$M$100 in the second argument of the function substitute but it's not working.
SUBSTITUTE(A2,$M$1:$M$100,"")
Where the column M contains "alm" alm1", ..., "alm100" etc.
This should work for you, it returned expected results on your provided sample data:
=IF(COUNTIF(A2,"*alm*")=0,A2,TRIM(SUBSTITUTE(A2&" ",MID(A2&" ",SEARCH("alm",A2),FIND(" ",A2&" ",SEARCH("alm",A2))),"")))
Excel has lousy string-handling capabilities. Regular expressions would make this task much easier.
In JavaScript, it's as simple as:
string.replace(/ *alm[0-9]+ */gi,'')
This does a global (g) case-insensitive (i) search of everything with:
0 or more spaces
followed by "alm" (in any case)
followed by 1 or more numbers
followed by 0 or more spaces
You can paste your data in the HTML box in this fiddle, and it will fix it:
http://jsfiddle.net/xs71bvan/2/

Excel Cross check 2 arrays with wildcard

I have no idea how to describe this but I'm so stuck and out of ideas so I will try.
I want to check if an item from one list is in another list that contains a wildcard
you can do the reversed thing with COUNTIF
example.
[LIST]
"Find ME Now",
"Find ME Later"
COUNTIF(LIST; "Find * Now")
This will result in a "match" because the wildcard is in the second argument.
But what i Want is the list to contain wildcards and still get a match
like
[LIST]
"Find * Now"
"Find * Later"
COUNTIF(LIST; "Find ME Now");
The above does now work but im trying to find something that does.
I made a VBA function that does what I want but that was running so slow because of a 1600 list * 10 list * 60 cells....
Edit:
I solved this problem with VBA and a global stored variable of results.
I think it might be worth sharing this even though #laxxen has a solution to the question.
You can set up a 'do-it-yourself' method of counting matches between the search string and the patterns. One formula I tried was the array formula
=SUM(--ISNUMBER(SEARCH($A$2:$A$5,B2)))
i.e. try the string in B2 with each of the wildcard patterns using SEARCH and count the number of positive results.
However I don't think this is quite right because SEARCH attempts a match at every position in the 'within' text, so if you want the case where it only matches starting at the beginning of the 'within' text, you need something like (another array formula)
=SUM(--IFERROR((SEARCH($A$2:$A$5,B2)=1),0))
This shows the results using the two formulae:-

Quick SQL question

Working on postgres SQL.
I have a table with a column that contains values of the following format:
Set1/Set2/Set3/...
Seti can be a set of values for each i. They are delimited by '/'.
I would like to show distinct entries of the form set1/set2 and that is - I would like to trim or truncate the rest of the string in those entries.
That is, I want all distinct options for:
Set1/Set2
A regular expression would work great: I want a substring of the pattern: .*/.*/
to be displayed without the rest of it.
I got as far as:
select distinct column_name from table_name
but I have no idea how to make the trimming itself.
Tried looking in w3schools and other sites as well as searching SQL trim / SQL truncate in google but didn't find what I'm looking for.
Thanks in advance.
mu is too short's answer is fine if the the lengths of the strings between the forward slashes is always consistent. Otherwise you'll want to use a regex with the substring function.
For example:
=> select substring('Set1/Set2/Set3/' from '^[^/]+/[^/]+');
substring
-----------
Set1/Set2
(1 row)
=> select substring('Set123/Set24/Set3/' from '^[^/]+/[^/]+');
substring
--------------
Set123/Set24
(1 row)
So your query on the table would become:
select distinct substring(column_name from '^[^/]+/[^/]+') from table_name;
The relevant docs are http://www.postgresql.org/docs/8.4/static/functions-string.html
and http://www.postgresql.org/docs/8.4/static/functions-matching.html.
Why do you store multiple values in a single record? The preferred solution would be multiple values in multiple records, your problem would not exist anymore.
Another option would be the usage of an array of values, using the TEXT[] array-datatype instead of TEXT. You can index an array field using the GIN-index.
SUBSTRING() (like mu_is_too_short showed you) can solve the current problem, using an array and the array functions is another option:
SELECT array_to_string(
(string_to_array('Set1/Set2/Set3/', '/'))[1:2], '/' );
This makes it rather flexible, there is no need for a fixed length of the values. The separator in the array functions will do the job. The [1:2] will pick the first 2 slices of the array, using [1:3] would pick slices 1 to 3. This makes it easy to change.
If they really are that regular you could use substring; for example:
=> select substring('Set1/Set2/Set3/' from 1 for 9);
substring
-----------
Set1/Set2
(1 row)
There is also a version of substring that understands POSIX regular expressions if you need a little more flexibility.
The PostgreSQL online documentation is quite good BTW:
http://www.postgresql.org/docs/current/static/index.html
and it even has a usable index and sensible navigation.
If you want to use .*/.* then you'd want something like substring(s from '[^/]+/[^/]+'), for example:
=> select substring('where/is/pancakes/house?' from '[^/]+/[^/]+');
substring
-----------
where/is
(1 row)

Resources