sqlite advanced case sensitive query - sqlite

i search for a special kind of query in SQLite
to sort a notes table.
The result from the query should be like this:
id oid
1 1
2 1,1
5 1,1,a
6 1,1,a,1
3 1,1,A
4 1,1,A,1
But with the folling code I receive this:
CREATE TABLE note (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
oid VARCHAR unique,
tit VARCHAR,
dsc VARCHAR
);
select id, oid from note
order by oid collate NOCASE
Result:
id oid
1 1
2 1,1
5 1,1,a
3 1,1,A
6 1,1,a,1
4 1,1,A,1
Any suggestions?
Thanks
--jonah

The following transforms the sort keys so that the normal case sensitive ordering yields the requested result:
If there was a togglecase() function, the function would uppercase lowercase and lowercase uppercase (for example Hello => hELLO), one could ORDER BY togglecase(oid) and the result would be in the order requested.
You could define such a function and expose it to SQLite as a UDF. It could also be possible to write this function using builtin SQLite functions but I don't know them well enough to give an answer using them. The following is an example of such a function in Python:
def togglecase(s):
def toggle(l):
if l.isupper():
return l.lower()
if l.islower():
return l.upper()
return l
return ''.join(toggle(l)
for l in s)
Note that for proper Unicode support it needs to iterate over graphemes. Not over code points.
See that this does what I described it to do:
>>> togglecase("1,1,A")
'1,1,a'
>>> togglecase("1,1,a")
'1,1,A'
It is possible to test if this sorts correctly in Python:
>>> sorted(["1", "1,1", "1,1,a", "1,1,a,1", "1,1,A", "1,1,A,1"])
['1', '1,1', '1,1,A', '1,1,A,1', '1,1,a', '1,1,a,1']
See how the uppercase follows the lowercase:
>> sorted(["1", "1,1", "1,1,a", "1,1,a,1", "1,1,A", "1,1,A,1"], key=togglecase)
['1', '1,1', '1,1,a', '1,1,a,1', '1,1,A', '1,1,A,1']
Now if you use it in SQLite like:
SELECT id, oid
FROM note
ORDER BY togglecase(oid)
This should result in:
1 "1"
2 "1,1"
3 "1,1,a"
4 "1,1,a,1"
5 "1,1,A"
6 "1,1,A,1"
The code is untested except for the togglecase function.

You are getting that result because the sorting is pecified to be NOCASE. That means that "a" and "A" are equals. So, first the rows with "a/A" and nothing after, and then rows with "a/A" and data after.
If you make the query CASE SENSITIVE, you will get a different result. BUT "A" comes befores "a" in case sensitive sort:
SELECT id, oid
FROM note
ORDER by oid
Results:
1 "1"
2 "1,1"
5 "1,1,A"
6 "1,1,A,1"
3 "1,1,a"
4 "1,1,a,1"

Related

SQLite select order by alphabet first, then all other characters

I have a SQLite db with a table, containing rows with different names. For example:
id
name
1
antony
2
%
3
10
4
stackoverflow
5
john
I get the data from this table with
SELECT * FROM table WHERE 1 ORDER BY name Asc LIMIT ?, ?
And it returns
id
name
2
%
3
10
1
antony
5
john
4
stackoverflow
But i want it to return names in alphabetical order first, then all other names which starts with non letters in the right order too. So i want to get:
id
name
1
antony
5
john
4
stackoverflow
2
%
3
10
How can i achieve that?
Use the operator GLOB to check if the name starts with a letter in the ORDER BY clause:
SELECT *
FROM tablename
ORDER BY name GLOB '[A-Za-z]*' DESC, name
See the demo.
Thanks to #forpas, just wish to add
If you wish to make Case insensitive sorting, you may try as below
SELECT *
FROM tablename
ORDER BY name GLOB '[A-Za-z]*' DESC, Upper(name)

SQLITE3 return count based on column's value

Example of my table :
ID MACHINE RESULT
1 A fail
2 A pass
3 B pass
4 A fail
The next query gets the number of pass and fail from all the MACHINE
SELECT RESULT, COUNT(*) FROM my_table GROUP BY RESULT
The answer is :
2 fail
2 pass
My goal is to get the pass and fail count from a specific MACHINE .
I tried the follow :
SELECT RESULT, COUNT(*) FROM my_table WHERE MACHINE = 'A' GROUP BY RESULT
It doesnt work as expected .
And I'm expecting :
2 fail
1 pass
Where is my mistake ? :<

SQLite does not order by two columns

Structure is:
CREATE TABLE stopsbuses (_id INTEGER PRIMARY KEY, stop_id NUMERIC, bus_id NUMERIC, drive TEXT, day TEXT);
CREATE TABLE stopsbusestimes (_id INTEGER PRIMARY KEY, sb_id NUMERIC, timeh NUMERIC, timem NUMERIC);
When I execute query like this:
SELECT timeh, timem FROM stopsbuses
INNER JOIN stopsbusestimes ON stopsbuses._id = stopsbusestimes.sb_id
WHERE stopsbuses.stop_id = 2 ORDER BY timeh asc, timem asc
Output for example is:
[..]
7 1
7 31
7 34
7 54
7 57
7 22
[..]
Same output is with simple:
SELECT timeh, timem FROM stopsbusestimes ORDER BY timeh, timem
Same output using php + pdo, SQLite Database Browser and in Android aplication.
Am i missing something in ordering by two columns?
In SQLite, all strings are sorted behind all numbers, so it's likely that 22 is not a number.
To see the types, try typeof or quote:
SELECT quote(timeh), quote(timem) FROM stopsbuses ...

sqlite returns 0 rows

SELECT skill_name, character_name, cb_id, cb_id2 FROM characterbasics, characterskills WHERE characterbasics.character_name = 'Joe' & characterbasics.cb_id = characterskills.cb_id2
This, for some reason, returns 0 rows
The character name is in there (as well as 2 other dummy names).. and both cbid and cbid2 are the same.
When i try the query without the & cbid=cbid2 i get the name with the other data.. now when i check for JUST cbid=cbid2 i get 3 different dummy characters i created...
im trying to pull all "skills" associated with one character by matching the id of the character name in table 1 with the character id in table 2
Where have I erred?
cn = character name
cn cbid cbid2
Joe 2 2
This is what it SHOULD look like..
You cant use & as logical AND operator (& is binary operator), so sql should look like :
SELECT skill_name, character_name, cb_id, cb_id2
FROM characterbasics, characterskills
WHERE characterbasics.character_name = 'Joe' AND characterbasics.cb_id = characterskills.cb_id2

How to set Sqlite3 to be case insensitive when string comparing?

I want to select records from sqlite3 database by string matching. But if I use '=' in the where clause, I found that sqlite3 is case sensitive. Can anyone tell me how to use string comparing case-insensitive?
You can use COLLATE NOCASE in your SELECT query:
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Additionaly, in SQLite, you can indicate that a column should be case insensitive when you create the table by specifying collate nocase in the column definition (the other options are binary (the default) and rtrim; see here). You can specify collate nocase when you create an index as well. For example:
create table Test
(
Text_Value text collate nocase
);
insert into Test values ('A');
insert into Test values ('b');
insert into Test values ('C');
create index Test_Text_Value_Index
on Test (Text_Value collate nocase);
Expressions involving Test.Text_Value should now be case insensitive. For example:
sqlite> select Text_Value from Test where Text_Value = 'B';
Text_Value
----------------
b
sqlite> select Text_Value from Test order by Text_Value;
Text_Value
----------------
A
b
C
sqlite> select Text_Value from Test order by Text_Value desc;
Text_Value
----------------
C
b
A
The optimiser can also potentially make use of the index for case-insensitive searching and matching on the column. You can check this using the explain SQL command, e.g.:
sqlite> explain select Text_Value from Test where Text_Value = 'b';
addr opcode p1 p2 p3
---------------- -------------- ---------- ---------- ---------------------------------
0 Goto 0 16
1 Integer 0 0
2 OpenRead 1 3 keyinfo(1,NOCASE)
3 SetNumColumns 1 2
4 String8 0 0 b
5 IsNull -1 14
6 MakeRecord 1 0 a
7 MemStore 0 0
8 MoveGe 1 14
9 MemLoad 0 0
10 IdxGE 1 14 +
11 Column 1 0
12 Callback 1 0
13 Next 1 9
14 Close 1 0
15 Halt 0 0
16 Transaction 0 0
17 VerifyCookie 0 4
18 Goto 0 1
19 Noop 0 0
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
You can do it like this:
SELECT * FROM ... WHERE name LIKE 'someone'
(It's not the solution, but in some cases is very convenient)
"The LIKE operator does a pattern
matching comparison. The operand to
the right contains the pattern, the
left hand operand contains the string
to match against the pattern. A
percent symbol ("%") in the pattern
matches any sequence of zero or more
characters in the string. An
underscore ("_") in the pattern
matches any single character in the
string. Any other character matches
itself or its lower/upper case
equivalent (i.e. case-insensitive
matching). (A bug: SQLite only
understands upper/lower case for ASCII
characters. The LIKE operator is case
sensitive for unicode characters that
are beyond the ASCII range. For
example, the expression 'a' LIKE 'A'
is TRUE but 'æ' LIKE 'Æ' is FALSE.)."
This is not specific to sqlite but you can just do
SELECT * FROM ... WHERE UPPER(name) = UPPER('someone')
Another option is to create your own custom collation. You can then set that collation on the column or add it to your select clauses. It will be used for ordering and comparisons.
This can be used to make 'VOILA' LIKE 'voilà'.
http://www.sqlite.org/capi3ref.html#sqlite3_create_collation
The collating function must return an integer that is negative, zero, or positive if the first string is less than, equal to, or greater than the second, respectively.
Another option that may or may not make sense in your case, is to actually have a separate column with pre-lowerscored values of your existing column. This can be populated using the SQLite function LOWER(), and you can then perform matching on this column instead.
Obviously, it adds redundancy and a potential for inconsistency, but if your data is static it might be a suitable option.
Its working for me Perfectly.
SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE
If the column is of type char then you need to append the value you are querying with spaces, please refer to this question here . This in addition to using COLLATE NOCASE or one of the other solutions (upper(), etc).
use like this
"select * from $pwsXDataHistory where type = '$type' COLLATE NOCASE and $t_uStatus != '$DELETE' order by $t_name COLLATE NOCASE asc ");
Simply, you can use COLLATE NOCASE in your SELECT query:
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
you can use the like query for comparing the respective string with table vales.
select column name from table_name where column name like 'respective comparing value';

Resources