I want to use full text search in sqlite3 and use a MATCH query. I created a virtual table with
CREATE VIRTUAL TABLE objects using fts5(guid, title, content); and I populated it.
This example works, but using "LIKE", for that I wouldn't even need FTS:
SELECT * FROM object WHERE content LIKE '%Angel%'
Using FTS, but MATCH does not return any results:
SELECT guid FROM object WHERE content MATCH 'Angel'
I have read here that we need to supply a custom function for MATCH to work. Hard to find good examples, so I used this one:
static void myMATCHfct(sqlite3_context *context, int argc, sqlite3_value **argv){
printf("myFunc fired!\n");
fflush(stdout);
}
int error = sqlite3_create_function( db, "match", 1, SQLITE_UTF8, NULL, myMATCHfct, NULL, NULL );
But it is not called. It is called though if I call it like a "normal" function, but this is not what I want:
SELECT match(guid) FROM object WHERE content LIKE '%Angel%'
What am I doing wrong?
Related
I am attempting to search for a key's value in MongoDB via my .c program. essentially In my collection in one of my documents: I have key:value, i want to be able to return said value by passing in the key. I have seen
query = bson_new ();
BSON_APPEND_UTF8 (query, "hello", "world");
cursor = mongoc_collection_find_with_opts( collection, query, NULL, NULL);
I want to be able to search using only hello and return world.
To query a value in MongoDB, with only one key and pair (ex. Key:Value). Regex can be used.
bson_t *query;
bson_append_regex(query, key, -1/* length of key*/, ".", NULL);
cursor = mongoc_collection_find_with_opts(collection, query, NULL, NULL);
The string "." in regex signifies 'any string', thus if you would need to find json value within another key such as:
{ key:
{
second_key:value
}
}
Changing the Regex to "second_key." would locate desired value.
Note
This will return any other values that may lay within, paired with mongoc_cursor_t * you can select the desired value you are looking for.
I'm using go-pg (https://github.com/go-pg/pg) and this code:
type Book struct {
id int
name string
}
var books []Book
err := db.Model(&books).Select()
and everything works good but I need to add a "virtual" column like this:
concat ('info:', 'id:', id, '...') AS info
and I tried to use:
query.ColumnExpr("concat ('info:', 'id:', id, '...') AS info")
but:
go-pg complains with: error="pg: can't find column=info in model=Book (try discard_unknown_columns)"
go-pg doesn't include anymore columns id and name in query: concat... ONLY!
I can understand that because now go-pg doesn't know how to bind data, but I really need that string which I can retrieve from DB only.
Is there a way?
Can I use a custom type like this below?
type CustomBook struct {
Info string
Book
}
Does this make sense?
this approach could work for you:
type Book struct {
ID int
Name string
Info string `pg:"-"`
}
...
db.Model(&books).ColumnExpr("book.*").ColumnExpr("CONCAT('id:', id, 'name:', name) AS info").Select()
pg:"-" ignores the struct field and it is not created nor it produces any errors
this ignored column is documented here: https://pg.uptrace.dev/models/
another approach, depending on your requirements could be like this:
var r []struct {
Name string
Info string
}
db.Model((*Book)(nil)).Column("name").ColumnExpr("CONCAT('id:', id, 'name:', name) AS info").Select(&r)
this second one is documented here: https://pg.uptrace.dev/queries/
According to the Dapper documentation, you can get a dynamic list back from dapper using below code :
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
((int)rows[0].A)
.IsEqualTo(1);
((int)rows[0].B)
.IsEqualTo(2);
((int)rows[1].A)
.IsEqualTo(3);
((int)rows[1].B)
.IsEqualTo(4);
What is however the use of dynamic if you have to know the field names and datatypes of the fields.
If I have :
var result = Db.Query("Select * from Data.Tables");
I want to be able to do the following :
Get a list of the field names and data types returned.
Iterate over it using the field names and get back data in the following ways :
result.Fields
["Id", "Description"]
result[0].values
[1, "This is the description"]
This would allow me to get
result[0].["Id"].Value
which will give results 1 and be of type e.g. Int 32
result[0].["Id"].Type --- what datattype is the value returned
result[0].["Description"]
which will give results "This is the description" and will be of type string.
I see there is a results[0].table which has a dapperrow object with an array of the fieldnames and there is also a result.values which is an object[2] with the values in it, but it can not be accessed. If I add a watch to the drilled down column name, I can get the id. The automatically created watch is :
(new System.Collections.Generic.Mscorlib_CollectionDebugView<Dapper.SqlMapper.DapperRow>(result as System.Collections.Generic.List<Dapper.SqlMapper.DapperRow>)).Items[0].table.FieldNames[0] "Id" string
So I should be able to get result[0].Items[0].table.FieldNames[0] and get "Id" back.
You can cast each row to an IDictionary<string, object>, which should provide access to the names and the values. We don't explicitly track the types currently - we simply don't have a need to. If that isn't enough, consider using the dapper method that returns an IDataReader - this will provide access to the raw data, while still allowing convenient call / parameterization syntax.
For example:
var rows = ...
foreach(IDictionary<string, object> row in rows) {
Console.WriteLine("row:");
foreach(var pair in row) {
Console.WriteLine(" {0} = {1}", pair.Key, pair.Value);
}
}
I have just 2 objects and simple query to retrieve the data.
The result of query which is stored in array ccList according to debug output is:
(
CustomThree__c:
{
Name=cusmei3 2,
customOne__c=a005000000IwnOPAAZ,
Id=a025000000FsFGQAA3
},
CustomThree__c:
{
Name=cusmei3 1,
customOne__c=a005000000IwnOUAAZ,
Id=a025000000FsFGLAA3
}
)
As you can see system.debug(ccList[0]) returns:
CustomThree__c:{
Name=cusmei3 2,
customOne__c=a005000000IwnOPAAZ,
Id=a025000000FsFGQAA3
}
But when I try to get Id (or other field) from the array, the error occurs.
Can anyone point out what am I doing wrong?
code
Object[] ccList;
ccList = [SELECT id, name, CustomOne__r.name FROM CustomThree__c];
system.debug(ccList);
system.debug('******************************************');
system.debug(ccList[0]);
system.debug(ccList[0].Id); //this one cause the error
I think you'll have to change the type of ccList from "Object" to "CustomThree__c". This will also give you compile-time checking when you'll try to write ccList[0].SomeNonExistentFieldName__c.
If you can't do it and really need the object that stores result to be generic - I believe this should be SObject?
My table has a timestamp column named "RowVer" which LINQ maps to type System.Data.Linq.Binary. This data type seems useless to me because (unless I'm missing something) I can't do things like this:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowVer > ???? );
So, one of the solutions I'm looking at is to add a new "calculated column" called RowTrack which is defined in SQL like this:
CREATE TABLE UserSession
(
RowVer timestamp NOT NULL,
RowTrack AS (convert(bigint,[RowVer])),
-- ... other columns ...
)
This allows me to query the database like I want to:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowTrack > 123456 );
Is this a bad way to do things? How performant is querying on a calculated column? Is there a better work-around?
Also, I'm developing against Sql Server 2000 for ultimate backwards compatibility, but I can talk the boss into making 2005 the lowest common denominator.
AS Diego Frata outlines in this post there is a hack that enables timestamps to be queryable from LINQ.
The trick is to define a Compare method that takes two System.Data.Linq.Binary parameters
public static class BinaryComparer
{
public static int Compare(this Binary b1, Binary b2)
{
throw new NotImplementedException();
}
}
Notice that the function doesn't need to be implemented, only it's name (Compare) is important.
And the query will look something like:
Binary lastTimestamp = GetTimeStamp();
var result = from job in c.GetTable<tblJobs>
where BinaryComparer.Compare(job.TimeStamp, lastTimestamp)>0
select job;
(This in case of job.TimeStamp>lastTimestamp)
EDIT:
See Rory MacLeod's answer for an implementation of the method, if you need it to work outside of SQL.
SQL Server "timestamp" is only an indicator that the record has changed, its not actually a representation of Date/Time. (Although it is suppose to increment each time a record in the DB is modified,
Beware that it will wrap back to zero (not very often, admittedly), so the only safe test is if the value has changed, not if it is greater than some arbitrary previous value.
You could pass the TimeStamp column value to a web form, and then when it is submitted see if the TimeStamp from the form is different to the value in the current record - if its is different someone else has changed & saved the record in the interim.
// Select all records that changed since the last time we inserted/updated.
Is there a better work-around?
Why not have two columns, one for createddate another for lastmodifieddate. I would say that is more traditional way to handle this scenario.
Following on from jaraics' answer, you could also provide an implementation for the Compare method that would allow it to work outside of a query:
public static class BinaryExtensions
{
public static int Compare(this Binary b1, Binary b2)
{
if (b1 == null)
return b2 == null ? 0 : -1;
if (b2 == null)
return 1;
byte[] bytes1 = b1.ToArray();
byte[] bytes2 = b2.ToArray();
int len = Math.Min(bytes1.Length, bytes2.Length);
int result = memcmp(bytes1, bytes2, len);
if (result == 0 && bytes1.Length != bytes2.Length)
{
return bytes1.Length > bytes2.Length ? 1 : -1;
}
return result;
}
[DllImport("msvcrt.dll")]
private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt);
}
The use of memcmp was taken from this answer to a question on comparing byte arrays. If the arrays aren't the same length, but the longer array starts with the same bytes as the shorter array, the longer array is considered to be greater than the shorter one, even if the extra bytes are all zeroes.