I am facing the following issue: I have an composite index on a database index1 {binaryColumn1, binaryColumn2}. I am using the following to set the index to use:
Api.JetSetCurrentIndex(_session, _table, index1);
to create the key:
Api.MakeKey(_session, _table, binaryValue, MakeKeyGrbit.NewKey);
and than try to perform the search with:
Api.TrySeek(_session, _table, SeekGrbit.SeekEQ);
This works and seek returns true correctly if index1 is only for 1 column. If I have multiple columns and try to search the value for a single column (ex. for binaryColumn1 = {0x01, 0x23}) it always returns false.
How can I search for this one value? (ps. I cannot change the index nor create new ones.) Is this possible?
Thank you
What you did would only work for {0x01, 0x00}. You can't do it with a single call, because the value of the second column will be mixing up the SeekEQ grbit.
You could do a SeekGE, but then you'll need to retrieve the column to make sure the value is actually correct (and not something like {0x22, 0x23}). You'll have to do something like:
SetCurrentIndex()
MakeKey( ..., binaryValue1, MakeKeyGrbit.NewKey | MakeKeyGrbit.FullColumnStartLimit); // Appends the rest of the search buffer with 0x00's.
Seek(GE);
MakeKey(... binaryValue1, MakeKeyGrbit.NewKey | MakeKeyGrbit.FullColumnEndLimit); // Appends the rest of the search buffer with 0xff's.
Api.JetSetIndexRange();
Then you can use Api.TryMoveNext() to iterate through all rows that have that column equal to binaryValue1.
Also look at the test code included with the project -- the HowDoI.cs file has lots of good examples.
Sorry for the pseudo-code; I don't have the source code handy at the moment.
-martin
Related
Want a query possibly a single query for the below conditions
To be updated value of column 3 and 4 is same for all 4 R2IGTNo column
Sometimes the blend will be up to 3 only, 4th row may not come
In C# application user will update for the first row (blend 1), other values have to be updated automatically since the values are the same.
I need a query, expert please help with this... Thanks
User picks row 1, this means your C# can know "Lot21009BB1C3" (putting text instead of image would have let me copy it, btw) but you write like the c# app doesn't know any other row..
Which means you can run a query:
UPDATE t SET HtrOnBy = #HtrOnBy, ChtrOnRemark = #ChtrOnRemark
WHERE R2IGTNo LIKE #R2IGTNo
And your c# shall put the following values:
#HtrOnBy = "Whatever it knows the first row HtrOnBy is"
#ChtrOnRemark = "Whatever it knows the first row ChtrOnRemark is"
#R2IGTNo = firstRowR2IGTNo.Remove(9) + "%"
We take the first 9 characters of R2IGTNo and add a percent. SQL will update all the rows that start with those, doesn't matter if it's 3 or 4 etc
If the number of chars varies, then you will have to get more smart about how you do your substring, such as looking for the first character after the numbers (eg regex)
I have a situation where values are missing from the rows returned by the scanner.
My key looks like this company_recordtype_recordid_childrecordtype_childrowid
the %id values are guids.
I am using C#, Azure HDInsights (HBase) and Microsoft.HBaseClient to do this work.
if I create a scanner like this
Scanner scanSettings = new Scanner()
{
batch = 10,
startRow = Encoding.UTF8.GetBytes(myrowkey),
endRow = Encoding.UTF8.GetBytes(myrowkey + "~")
};
where myrowkey looks like companya_salesrecord_guid_receipt_
Start looks like that and End looks like companya_salesrecord_guid_receipt_guid(s) where guid(s) means that there are many receipts for that salesrecord (just a goofy example)
And if I want to look up all the receipts associated to that salesrecord it should bring back all the row values, or so I think.
Now each row has at minimum 8 columndata values, because they are required and I have verified that they exist. I also have a hive cover table over this and it shows them all, no partial weird rows. Only NULLS in HiveTable where values don't exist and full values where they do.
When I do the actual code run, I randomly get rows that only have say... 3 row values in them, while 99% of them are all 8 row values.
if I then take the full key to the row of data that has only partial values (like 3).. and use the exact same code, but qualify the entire key, I get all the values.
I am completely lost as how to resolve this... or even debug this, so any thoughts are truly appreciated.
You probably misunderstood what batch parameter of a Scan means. The batch parameter sets how many cells the scan returns on each RPC call and it is usually used only when you have rows with a large number of columns. What you really wanted is the caching parameter — it controls how many rows the scan gets per one RPC.
I am trying to reset the number of columns in an Excel ListObject. I know you can add and remove columns one-by-one, but I want to avoid unnecessary loops. I instead decided to resize the ListObject using the Resize method.
Here is the code that I am using (where OutputCasesTable is the ListObject):
OutputCasesTable.DataBodyRange.Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
The above lines of code appear to work perfectly, however if the ListObject only contains 1 row of data, the DataBodyRange of the ListObject becomes null on the second line - producing an error when I try to change its cell's value. The row in excel still appears to be present.
The MSDN documentation says the following:
"The header must remain in the same row and the resulting list must overlap the original list. The list must contain a header row and at least one row of data."
Now I understand that "one row of data" implies that the row contains values - so the cause of the error here must be that the DataBodyRange cells all contain no value (""). However, a table with two data rows containing "" still doesn't have a row with data, does it?
I know there are many ways of accomplishing this task, but I want to understand why this happens.
Temporary Solution:
Replaced the code to only set the values to empty strings in columns that will be removed (columns above the new column count). All other columns will be replaced:
if(OutputCasesTable.ListColumns.Count - CaseCount > 0)
OutputCasesTable.DataBodyRange.Offset[ColumnOffset: CaseCount].Resize[ColumnSize: OutputCasesTable.ListColumns.Count - CaseCount].Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
Personally I prefer looking at the first solution!
Is there anything I can do make it work with empty strings? Or do you have a better solution?
Best regards,
The Resize operation is the piece that kills the DataBodyRange, and clearly there's some internal logic that Resize uses, along the lines of "if there is only one row, and all the cells are empty, remove all the data rows. If there is more than one row, don't remove any".
I agree that this logic is a bit confounding. If your question is why did Microsoft implement it this way, I'd argue that although it's inconsistent, it's perhaps tidier in a way - it appears to the model that you're working with an empty table, and there's no way for the model to tell the difference graphically (it's not possible for a table to just have a header row).
When Resize turns up to do its work and finds a single-row blank table, it can't tell whether you have a zero-row table or a single-row table with empty strings. If it arrives and finds two empty rows, that's unambiguous (they must be meaningful rows).
For the workaround portion of your question, I'd suggest a tidier solution of just checking the ListRows.Count property, and adding one if necessary. Note that you can also use Clear instead of setting Value2 to blank; for me it reads as more self-explanatory.
OutputCasesTable.DataBodyRange.Clear();
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
if (OutputCasesTable.ListRows.Count == 0) OutputCasesTable.ListRows.Add();
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
I´m trying to set a cell of type "System.Int32" in a DataSet by code, and my try looks like this:
int aCarID = 5; // as an example...
// points out the row that I want to manipulate - I guess this is what doesn´t work???
int insertIndex = myDataSet.tableCars.Rows.Count
myDataSet.tableCars.Rows[insertIndex]["CarID"] = aCarID;
What happens is: I get an exception of "System.IndexOutOfRangeException".
You´re allowed to say that I´m stupid as long as you provide an answer...
UPDATE!
Yes, I´m trying to create a new row, that´s true - that´s why I´m not using "-1".
So what´s the syntax to create a new row?
If I use tableCars.Rows.Add(...) I need to supply a "DataRow Row" to the Add-function, and I don´t have one to provide - yet! (Catch 22)
NEW UPDATE!
Ooops, found it - "NewRow()" :-)
You do realize that indices start with zero in C#? That means if your table has 3 rows, you're trying to access the 4th row because insertIndex = 3.
Try insertIndex - 1.
Edit: Since you're trying to add a new row and already found out how to do so, also don't forget to save those changes to the database (I assume that's what you want to do). The most simple way is to set the UpdateCommand-property of the DataAdapter you used to fill the DataSet (or actually the DataTable in the DataSet).
You can also have the update commands generated, using a subclass of the DbCommandBuilder.
This is a classic off-by-one: valid rows are at indices 0... Rows.Count -1
If you want to make a new row, call tableCars.AddNew() first.
From MSDN:
An IndexOutOfRangeException exception is thrown when an attempt is made to access an element of an array or collection with an index that is outside the bounds of the array or less than zero.
so the problem is when you use a wrong index as Christian said.
try to create new row first, because you want to access row which doesn't exists, or you have to insert your information into row indexed (insertIndex - 1).
Datarow indexes first position is 0, as in arrays.
You're using a strong-typed dataset, but your insert code is actually for a non-strongly typed dataset.
The following code will work for you (and is much easier!)
var insertRow = myDataSet.tableCars.NewtableCarsRow();
insertRow.CarID = aCarID;
myDataSet.AcceptChanges();
That's it!
NOTE: this code works from .NET version 3.5 onwards. For prior versions, replace the var keyword with tableCarsRow (I'm assuming that you didn't customize the default name for the datarow in the DataSet designer).
Is it possible to get the information why/how given row returned by FTS query was matched (or which substring caused row to match)?
For example, consider simpliest table with id and text columns, with FTS index on the later one.
SELECT * FROM Example
WHERE CONTAINS(text, 'FORMSOF(INFLECTIONAL, jump)');
This examplary query could return, say row {1, 'Jumping Jack'}.
Now, is it possible to somehow get information that this very row was matched because of 'Jumping' word? It doesn't even have to be exact information, more of a which substring caused row to match.
Why I'm asking - I got C# app that builds up those queries basing on user input (keywords to search for), and I need the very basic information why/how row was matched back, to use further in C# code.
If it's not possible, any alternatives?
EDIT in regards of Mike Burton's and LesterDove's replies:
The above example was trivial for obvious reasons and your solutions are ok having that in mind, however FTS queries might return results where regex or simple string matching (eg. LIKE) won't cut in. Consider:
Search for bind returns bound (past form).
Search for extraordinary returns amazing (synonym).
Both valid matches.
I've been looking for solutions to this problem and found this: NHunspell. However, I already got FTS & valid results using SQL Server, duplicating similar mechanism (building extra indexes, storing additional words/thezaurus files etc) doesn't look good.
Lester's answer however gave me some ideas that perhaps I could indeed split the original string to temporary table, and run the original FTS query on this split result. As it might work for my case (where DB is fairly small and queries are not very complex), in general case this approach might be out of question.
1/ Use a SPLIT function (many variations can be Googled) on your original substring, which will dump the individual substrings into a temp table of some sort, with one row per substring snippet.
2/ EDIT: You need to use CROSS APPLY to join to a table valued function:
SELECT * FROM Example E CROSS APPLY Split(E.text, ' ') AS S
WHERE CONTAINS(E.text, 'FORMSOF(INFLECTIONAL, jump)') AND S.String LIKE '%jump%';
*NOTE: You need to forage for your own user-defined Split function. I used this one and applied the first commenter's edit to allow for the space character as a delimiter.
So, E is your Example table. You're still FT searching on the text field for the word 'jump'. And now you're "joining" to a table comprised of the individual substring values of your text field. Finally, you're matching that against the word 'jump' by using LIKE or Instr.
One simple post-processing method would be to generate an equivalent Regular Expression for each WHERE clause article and use it to discover after the fact how the found data matches the specified pattern.
You can get SQL to tell you how it interpreted your query, including how it transformed your input.
SELECT occurrence, special_term, display_term, expansion_type, source_term
FROM sys.dm_fts_parser('FORMSOF(INFLECTIONAL, bind)', 1033, 0, 0)
returns
occurrence special_term display_term expansion_type source_term
1 Exact Match binds 2 bind
1 Exact Match binding 2 bind
1 Exact Match bound 2 bind
1 Exact Match bind 0 bind
This isn't precisely what you asked for, but it's a start. You could search your results for anything in the display_term column and probably figure out why it matched.