Getting the values and column names of an INSERT object in the Java Cassandra Driver - cassandra

I have a Insert object created as follows:
Insert insert = QueryBuilder.insertInto("demo", "users");
insert.value("name", name);
insert.value("sport", "test");
insert.value("years", 2);
insert.value("vegetarian", true);
Somewhere else in my code, I need to get the list of names and values associated with this INSERT object. When I debug the code I can see two "values" and "names" ArrayLists that contain the information I need, however they are private and I cannot access them.
While insert.getObject(0); gets the object from the values ArrayList, I can't map the value to a column name. Furthermore insert.getValues(ProtocolVersion.V4, CodecRegistry.DEFAULT_INSTANCE); seems to serialize the objects and put them into a ByteBuffer which is not desirable.

I recommend to use the PreparedStatement & BoundStatement instead of simple Insert. First, you can get better performance if you're inserting a lot of data. And second - you'll be able to get a list of variables defined in prepared statement, together with associated values

Related

How to use BQL In Operator with Select2 query / PXProjection and list of values

I am trying to replicate the following type of SQL query that you can perform in SQL Server...the important part here is the WHERE clause:
Select InventoryCD from InventoryItem WHERE InventoryCD IN ('123123', '154677', '445899', '998766')
It works perfectly using the IN3<> operator and a series of string constants:
i.e. And<InventoryItem.inventoryCD, In3<constantA,constantB,constantC>,
However, I need to be able to do this with an arbitrarily long list of values in an array, and I need to be able to set the values dynamically at runtime.
I'm not sure what type I need to pass in to the IN<> statement in my PXProjection query. I have been playing around with the following approach, but this throws a compiler error.
public class SOSiteStatusFilterExt : PXCacheExtension<SOSiteStatusFilter>
{
public static bool IsActive()
{
return true;
}
public abstract class searchitemsarray : PX.Data.IBqlField
{
}
[PXUnboundDefault()]
public virtual string[] Searchitemsarray { get; set; }
}
I think maybe I need an array of PXString objects? I'm really not sure, and there isn't any documentation that is helpful. Can anyone help?
This shows how to do it with a regular PXSelect: https://asiablog.acumatica.com/2017/11/sql-in-operator-in-bql.html
But I need to be able to pass in the correct type using Select2...
For reference I will post here the example mentioned by Hugues in the comments.
If you need to generate a query with an arbitrary list of values generated at runtime like this:
Select * from InventoryItem InventoryItem
Where InventoryItem.InventoryCD IN ('123123', '154677', '445899', '998766')
Order by InventoryItem.InventoryCD
You would write something like this:
Object[] values = new String[] { "123123", "154677", "445899", "998766" };
InventoryItem item = PXSelect<InventoryItem,
Where<InventoryItem.inventoryCD,
In<Required<InventoryItem.inventoryCD>>>>.Select(Base, values);
Please note that In<> operator is available only with Required<> parameter and you need to pass array of possible values manually to Select(…) method parameters. So you need to fill this array with your list before calling the Select method.
Also, the Required<> parameter should be used only in the BQL statements that are directly executed in the application code. The data views that are queried from the UI will not work if they contain Required<> parameters.
I ended up creating 100 variables and using the BQL OR operator, i.e.
And2<Where<InventoryItem.inventoryCD, Equal<CurrentValue<SOSiteStatusFilterExt.Pagefilter1>>,
Or<InventoryItem.inventoryCD, Equal<CurrentValue<SOSiteStatusFilterExt.Pagefilter2>>,
Or<InventoryItem.inventoryCD, Equal<CurrentValue<SOSiteStatusFilterExt.Pagefilter3>>,
Or<InventoryItem.inventoryCD, Equal<CurrentValue<SOSiteStatusFilterExt.Pagefilter4>>,
etc...etc...
You can then set the value of Pagefilter1, 2, etc inside of the FieldSelecting event for SOSiteStatusFilter.inventory, as an example. The key insight here, which isn't that obvious to the uninitiated in Acumatica, is that all variables parameterized in SQL Server via BQL are nullable. If the variable is null when the query is run, SQL Server automatically disables that variable using a "bit flipping" approach to disable that variable in the SQL procedure call. In normal T-SQL, this would throw an error. But Acumatica's framework handles the case of a NULL field equality by disabling that variable inside the SQL procedure before the equality is evaluated.
Performance with this approach was very good, especially because we are querying on an indexed key field (InventoryCD isn't technically the primary key but it is basically a close second).

Android Studio Room query to get a random row of db and saving the rows 2nd column in variable

like the title mentions I want a Query that gets a random row of the existing database. After that I want to save the data which is in a specific column of that row in a variable for further purposes.
The query I have at the moment is as follows:
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
fun getRandomRow()
For now I am not sure if this query even works, but how would I go about writing my function to pass a specific column of that randomly selected row to a variable?
Ty for your advice, tips and/or solutions!
Your query is almost correct; however, you should specify a return type in the function signature. For example, if the records in the data_table table are mapped using a data class called DataEntry, then the query could read as shown below (note I've also added the suspend modifier so the query must be run using a coroutine):
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): DataEntry?
If your application interacts with the database via a repository and view model (as described here: https://developer.android.com/topic/libraries/architecture/livedata) then the relevant methods would be along the lines of:
DataRepository
suspend fun findRandomEntry(): DataEntry? = dataEntryDao.getRandomRow()
DataViewModel
fun getRandomRecord() = viewModelScope.launch(Dispatchers.IO) {
val entry: DataEntry? = dataRepository.findRandomEntry()
entry?.let {
// You could assign a field of the DataEntry record to a variable here
// e.g. val name = entry.name
}
}
The above code uses the view model's coroutine scope to query the database via the repository and retrieve a random DataEntry record. Providing the returning DataEntry record is not null (i.e. your database contains data) then you could assign the fields of the DataEntry object to variables in the let block of the getRandomRecord() method.
As a final point, if it's only one field that you need, you could specify this in the database query. For example, imagine the DataEntry data class has a String field called name. You could retrieve this bit of information only and ignore the other fields by restructuring your query as follows:
#Query("SELECT name FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): String?
If you go for the above option, remember to refactor your repository and view model to expect a String instead of a DataEntry object.

Inserting data into database with python/sqlite3 by recognising the column name

I've got a problem that I don't know how to solve, I've tried many solutions but always getting that Operational error: near...
def insert_medicine_to_table():
con = sqlite3.connect('med_db3.db')
cur = con.cursor()
table_name = 'medicines'
column_name = "présentation"
value = 'Boîte de 2 seringues pré-remplies'
cur.execute("INSERT INTO medicines {} VALUES (?)".format(column_name), value)
con.commit()
con.close()
sqlite3.OperationalError: near "présentation": syntax error
The goal here is that either the script or python has to recognize the field (column name) and insert the value into "that" field, like the following:
fields = ['présentation', 'princeps', 'distributeur_ou_fabriquant', 'composition', 'famille', 'code_atc', 'ppv', 'prix_hospitalier', 'remboursement', 'base_de_remboursement__ppv', 'nature_du_produit']
values = ['Boîte de 2 seringues pré-remplies', 'Oui', 'SANOFI', 'Héparine', 'Anticoagulant héparinique', 'B01AB01', '43.80', '27.40', 'Oui', '43.80', 'Médicament']
That is one entry in the database. The problem here is that other entries can or not have one or more values for some field, and also the fields are not presented in the same order in other entries.
It has to recognize each field in the database table and insert each value into the right column.
The problem causing your error is that your SQL isn't valid. The statement you are trying to execute is:
INSERT INTO medicines présentation VALUES (?)
The statement you want to execute is:
INSERT INTO medicines ("présentation") VALUES (?)
As far as your larger question is concerned, if you create both the list of columns ("présentation") and list of parameter markers (?) and build the query using them, you're most of the way there.
If a field can have multiple values supplied for each "entry" in your database, you may need to change your database design to handle that. You'll at least need to figure out how you want to handle the situation, but that would be a matter for a different question.

How to deserialize DynamicComposite column value?

I am trying to implement a data model where row keys are Strings, column names are Longs and column values are DynamicComposites. Using Hector, an example of the stored procedure looks like this:
// create the value
DynamicComposite colVal = new DynamicComposite();
colVal.add(0, "someString");
colVal.setComparatorByPosition(0, "org.apache.cassandra.db.marshal.UTF8Type");
colVal.setSerializerByPosition(0, StringSerializer.get());
// create the column
HColumnImpl<Long, DynamicComposite> newCol = new
HColumnImpl<Long, DynamicComposite>(longSerializer,
dynamicCompositeSerializer);
newCol.setName(longValue);
newCol.setValue(colVal);
newCol.setClock(keySpace.createClock());
// insert the new column
Mutator<String> mutator = HFactory.createMutator(keySpace,stringSerializer);
mutator.addInsertion("rowKey","columnFamilyName",newCol);
mutator.execute();
Now, when I try to retrieve the data:
// create the query
SliceQuery<String,Long,DynamicComposite> sq =
HFactory.createSliceQuery(keySpace, stringSerializer, longSerializer,
dynamicCompositeSerializer);
// set the query
sq.setColumnFamily("columnFamilyName");
sq.setKey("rowKey");
sq.setColumnNames(longValue);
// execute the query
QueryResult<ColumnSlice<Long, DynamicComposite>> qr = sq.execute();
// get the data
qr.get().getColumnByName(longValue).getValue();
or when I just try to get plain byes:
// get the data
dynamicSerializer.fromByteBuffer(qr.get().
getColumnByName(longValue).getValueBytes());
I run into an exception:
Exception in thread "main" java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.common.collect.ImmutableClassToInstanceMap.getInstance(ImmutableClassToInstanceMap.java:147)
at me.prettyprint.hector.api.beans.AbstractComposite.serializerForComparator(AbstractComposite.java:321)
at me.prettyprint.hector.api.beans.AbstractComposite.getSerializer(AbstractComposite.java:344)
at me.prettyprint.hector.api.beans.AbstractComposite.deserialize(AbstractComposite.java:713)
at me.prettyprint.hector.api.beans.DynamicComposite.fromByteBuffer(DynamicComposite.java:25)
at me.prettyprint.cassandra.serializers.DynamicCompositeSerializer.fromByteBuffer(DynamicCompositeSerializer.java:35)
As far as I have understood from all the tutorials I read, it should be possible to use DynamicComposite as column value. Therefore I want to ask: what am I doing wrong? From the exception it seems I am just forgetting to set something somewhere.
Radovan,
Its probably due to compatibility issues of the Guava library used in conjuction with the Hector version.
See also : https://github.com/hector-client/hector/pull/591
I am on Hector-core-1.1-1.jar, in combination with the Guava-14.0.jar I get the same error as you. When I use it with the Guava-12.0.1.jar however it works fine for me.

Subsonic 3: Strongly typed return value for stored procedures that return mixed results from different tables

Say I have a stored procedure that returns dataSet from 2 different tables. Example:
SELECT Customers.FirstName, Customers.LastName, SUM(Sales.SaleAmount) AS SalesPerCustomer
FROM Customers LEFT JOIN Sales
ON Customers.CustomerID = Sales.CustomerID
GROUP BY Customers.FirstName, Customers.LastName
Is there any way to get a strongly typed list as a result from this stored procedure ? Something like this:
StoredProcedure sp = myDevDB.GetCustomerSales();
List<MyCustomType> resultSet = sp.ExecuteTypedList<MyCustomType>();
How and where do I define the MyCustomType class ? How do I map its properties to the actual table columns ?
thanks,mehul
I solved it by creating a class (in the same place as all my other classes, but I didn't extend IActiveRecord, it's just a vanilla class).
Make sure the property names have exactly the same name and data type as the ones in the procedure, then call db.sproc(params).ExecuteTypedList().AsQueryable(); and it populated fine.

Resources