I have the following code:
try (DB db = new DB()) {
db.open(cpds);
// Using the metadata to walk down the tree and identify all
// children nodes to the leaf tables.
// First the metadata for the pk of the target table
List<Integer> recordIdList = new ArrayList<Integer>();
recordIdList.add(recordId);
batchInsertDeletePks(recordIdList, db);
List<Integer> pkValues = new ArrayList<Integer>();
pkValues.add(recordId);
prepareChildDeletes(tablemeta_id, pkValues, recordId, db);
ColumnData.delete("RECORD_ID IN (SELECT ID FROM TEMPDELETE)");
noDeleted = RecordData.delete("ID IN (SELECT ID FROM TEMPDELETE)");
TempDelete.deleteAll();
} catch (Exception ex) {
logger.debug(ex.getMessage());
}
The TEMPDELETE has all of the primary keys I need to delete from COLUMNDATA. The ColumnData.delete is not working, the RecordData.delete is not working and the TempDelete.deleteAll is not working. They give no exceptions. The database is h2-1.4.196
If I debug trace into them and cut and paste the SQL that is created and run that SQL in a sql interpreter all the queries work just fine.
I cannot see what it is about my approach that is different to the examples? Any ideas?
Related
I'm a beginner at Hibernate and I would like to do a select from in more than two tables using CriteriaQuery.
I have 3 tables: Cellphone, CellphoneIamges and CellphoneRangedPrices and
I would like to get the data from these three tables.
One example: This query below get the data from tables:
Select cellphone.cellphoneID, cellphone.cellphoneName, cellphoneImages.cellphoneImageID, cellphoneImages.cellphoneImageInternalLink,
cellphoneImages.cellphoneImageExternalLink, cellphoneRangedPrices.cellphoneRangedPricesID, cellphoneRangedPrices.cellphoneRangedPriceStart, cellphoneRangedPrices.cellphoneRangedPriceEnd
FROM cellphone, cellphoneImages, cellphoneRangedPrices
WHERE cellphone.cellphoneID = cellphoneImages.cellphoneID AND cellphone.cellphoneID = cellphoneRangedPrices.cellphoneID;
But I would like get it using CriteriaQuery. I tried do it.
public List getAllCellphoneData(){
EntityManager em = mySQLDAO.getEm();
try {
CriteriaQuery<Object[]> criteriaQuery = em.getCriteriaBuilder().createQuery(Object[].class);
Root<Cellphone> rootPhone = criteriaQuery.from(Cellphone.class);
Root<CellphoneImages> rootImages = criteriaQuery.from(CellphoneImages.class);
criteriaQuery.multiselect(rootImages,rootPhone);
criteriaQuery.where(em.getCriteriaBuilder().equal(rootImages.get("cellphone"), rootPhone.get("cellphoneID")));
Query query = em.createQuery(criteriaQuery);
List<Object[]> resultList = query.getResultList();
return null;
} catch (Exception e) {
logger.log(Level.SEVERE, "Error when trying get cellphone information.", e);
throw new PersistenceException(e);
} finally {
em.close();
}
}
It's working, but I don't know how to add more one class in this criteriaQuery.
I would like help to understand how to do it.
Actually the method above can get data from Cellphone and CellphoneImages tables, but I don't know what I need do in code to get data from another table (CellphoneRangedPrices).
I tried search in other stackoberflow post but I don't find.
NOTE: the table CellphoneRagedPrice has foreign key from Cellphone table (Similar to CellphoneImages table)
Thank so much for your help
I found the solution for my question.
Basically I need add into same "WHERE" clause the other .Class from third table.
criteriaQuery.multiselect(rootPhone,rootImages,rootRangedPrices);
criteriaQuery.where(em.getCriteriaBuilder().equal(rootImages.get("cellphone"), rootPhone.get("cellphoneID")),
em.getCriteriaBuilder().equal(rootPhone.get("cellphoneID"), rootRangedPrices.get("cellPhone")));
Follow below the complete code:
public List<CellphoneVO> getAllCellphoneData(){
EntityManager em = mySQLDAO.getEm();
List<CellphoneVO> cellphoneVOList = new ArrayList<>();
try {
CriteriaQuery<Object[]> criteriaQuery = em.getCriteriaBuilder().createQuery(Object[].class);
Root<Cellphone> rootPhone = criteriaQuery.from(Cellphone.class);
Root<CellphoneImages> rootImages = criteriaQuery.from(CellphoneImages.class);
Root<CellphoneRangedPrices> rootRangedPrices = criteriaQuery.from(CellphoneRangedPrices.class);
criteriaQuery.multiselect(rootPhone,rootImages,rootRangedPrices);
criteriaQuery.where(em.getCriteriaBuilder().equal(rootImages.get("cellphone"), rootPhone.get("cellphoneID")),
em.getCriteriaBuilder().equal(rootPhone.get("cellphoneID"), rootRangedPrices.get("cellPhone")));
Query query = em.createQuery(criteriaQuery);
List<Object[]> resultList = query.getResultList();
for(Object[] objects : resultList){
CellphoneVO cellphoneVO = new CellphoneVO();
Cellphone cellphone = (Cellphone)objects[0];
CellphoneImages cellphoneImages = (CellphoneImages)objects[1];
CellphoneRangedPrices cellphoneRangedPrices = (CellphoneRangedPrices)objects[2];
cellphoneVO.setCellphone(cellphone);
cellphoneVO.setCellphoneImages(cellphoneImages);
cellphoneVO.setCellphoneRangedPrices(cellphoneRangedPrices);
cellphoneVOList.add(cellphoneVO);
}
return cellphoneVOList;
} catch (Exception e) {
logger.log(Level.SEVERE, "Error when trying get cellphones data.", e);
throw new PersistenceException(e);
} finally {
em.close();
}
}
Can any one let me know whether UpdateTableSpec can only update KeySchema attributes and is there any way to update/modify a table with non-keyschema attributes ? My scenario is : I created a table with composite key comprising of a primary ( #id attribute) and range key ( #Name attribute). Now I want to add a third attribute, Gender, which is not a part of keyschema. Is it possible ?
I am updating my DynamoDB table using the following code but it does not add the Gender attribute, although it successfully updates the provisioned attribute:
static void updateTable() {
System.out.println("Updating the table with new attributes ...");
Table table = dynamoDB.getTable(tableName);
UpdateTableSpec updateTableSpec = new UpdateTableSpec();
List<AttributeDefinition> attributeDefinitionList = updateTableSpec.getAttributeDefinitions();
if (null == attributeDefinitionList) {
attributeDefinitionList = new ArrayList<AttributeDefinition>();
}
attributeDefinitionList.add(new AttributeDefinition()
.withAttributeName("Gender")
.withAttributeType("S"));
updateTableSpec.withAttributeDefinitions(attributeDefinitionList)
.withProvisionedThroughput(new ProvisionedThroughput()
.withReadCapacityUnits(6L)
.withWriteCapacityUnits(7L));;
table.updateTable(updateTableSpec);
try {
table.waitForActive();
System.out.println("Table updated succesfully");
} catch (final Exception ex) {
System.out.println("Exception occurred while updating the table");
}
}
You cannot update key schema for a DynamoDB table. Update Table API can be used only for (from the doc):
Modify the provisioned throughput settings of the table.
Enable or disable Streams on the table.
Remove a global secondary index from the table.
Create a new global secondary index on the table. Once the index begins backfilling, you can use UpdateTable to perform other operations.
Your best option, I think, is to migrate to a new table with the desired new key schema. You can see other options here.
I have a DynamoDB table that contains videos info.
Currently "videoID"is the primary (hash) key and "Category" is the range (sort) key.
I want to get a list of all of the "Categories" (Range keys) so I can allow the user to select from one of the available video categories.
https://www.quora.com/What-are-some-good-ways-to-extract-one-single-column-from-a-DynamoDB-table
I was reading that if you modified change the attribute "Category" to a global secondary index you can return the items for that GSI. But I have not been able to find how to do that.
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSIJavaDocumentAPI.html
So I guess that gives me three questions:
Is there a way to do to find the items in Category by querying just the range key?
If change Category to a GSI can I fiind the items that way?
or
Is the only way of doing it scanning the whole table?
Thanks in advance for your help
Is the only way of doing it scanning the whole table?
-NO, you can implement GSI to avoid it
Is there a way to do to find the items in Category by querying just the range key?
- Yes, If you don't want to scan entire table then you need to create GSI which will have Category as Hash. This GSI will act as a table in itself and you can query on it by passing category values.
If change Category to a GSI can I find the items that way?
-Yes, you can query on GSI with category values
I was reading that if you modified change the attribute "Category" to a global secondary index you can return the items for that GSI. But I have not been able to find how to do that.
-You need to create GSI when you create table, example is given in the link that you have specified once that is done you can query that GSI
References:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html
Here is the sample code to create Videos table with GSI.
Create "Videos" table with GSI:-
#Autowired
private AmazonDynamoDBClient dynamoDBClient;
public Boolean createTableWithGlobalSecondaryIndex(String tableName) {
CreateTableRequest createTableRequest = null;
DynamoDB dynamoDB = new DynamoDB(dynamoDBClient);
try {
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("videoid").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("category").withAttributeType("S"));
ArrayList<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
keySchema.add(new KeySchemaElement().withAttributeName("videoid").withKeyType(KeyType.HASH));
keySchema.add(new KeySchemaElement().withAttributeName("category").withKeyType(KeyType.RANGE));
// Initial provisioned throughput settings for the indexes
ProvisionedThroughput ptIndex = new ProvisionedThroughput().withReadCapacityUnits(150L)
.withWriteCapacityUnits(150L);
GlobalSecondaryIndex videoCategoryGsi = new GlobalSecondaryIndex().withIndexName("VideoCategoryGsi")
.withProvisionedThroughput(ptIndex)
.withKeySchema(new KeySchemaElement().withAttributeName("category").withKeyType(KeyType.HASH),
new KeySchemaElement().withAttributeName("videoid").withKeyType(KeyType.RANGE))
.withProjection(new Projection().withProjectionType(ProjectionType.ALL));
createTableRequest = new CreateTableRequest().withTableName(tableName).withKeySchema(keySchema)
.withAttributeDefinitions(attributeDefinitions)
.withProvisionedThroughput(
new ProvisionedThroughput().withReadCapacityUnits(100L).withWriteCapacityUnits(100L))
.withGlobalSecondaryIndexes(videoCategoryGsi);
Table table = dynamoDB.createTable(createTableRequest);
table.waitForActive();
} catch (ResourceInUseException re) {
if (re.getErrorMessage().equalsIgnoreCase("Cannot create preexisting table")) {
LOGGER.info("Table already exists =============>" + tableName);
} else if (re.getErrorMessage().contains("Table already exists")) {
LOGGER.info("Table already exists =============>" + tableName);
LOGGER.info("Message =============>" + re.getErrorCode() + ";" + re.getErrorMessage());
} else {
throw new RuntimeException("DynamoDB table cannot be created ...", re);
}
} catch (Exception db) {
throw new RuntimeException("DynamoDB table cannot be created ...", db);
}
return true;
}
Query GSI by category:-
Here is the input is just category and it is querying using GSI. In other words, it is not scanning the entire table as well.
public List<String> findVideosByCategoryUsingGlobalSecondaryIndex(String category) {
List<String> videoAsJson = new ArrayList<>();
DynamoDB dynamoDB = new DynamoDB(dynamoDBClient);
Table table = dynamoDB.getTable("Videos");
Index index = table.getIndex("VideoCategoryGsi");
ItemCollection<QueryOutcome> items = null;
QuerySpec querySpec = new QuerySpec();
querySpec.withKeyConditionExpression("category = :val1")
.withValueMap(new ValueMap()
.withString(":val1", category));
items = index.query(querySpec);
Iterator<Item> pageIterator = items.iterator();
while (pageIterator.hasNext()) {
String videoJson = pageIterator.next().toJSON();
System.out.println("Video json ==================>" + videoJson);
videoAsJson.add(videoJson);
}
return videoAsJson;
}
I am developing an Android application with an SQLite3 database holding some of the data for offline access. I am trying to query the database using rawQuery, and a WHERE clause querying for a String. However, it's not returning any results, and neither is SQLite3 on the command line using the same Query, however a copy of the database in MySQL format executes the query just fine and gets the correct results.
Here is my code:
String query = "SELECT id FROM plaques WHERE subject = ?";
String subjectName = "Florence Nightingale";
Cursor cursor = db.rawQuery(query, new String[]{subjectName});
if (cursor.moveToFirst()) {
do {
try {
int id = cursor.getInt(cursor.getColumnIndex("id"));
} catch (Exception e) {
e.printStackTrace();
}
} while (cursor.moveToNext());
}
cursor.close();
(the database is being selected, using the Context and this is working).
So the query (SELECT id FROM plaques WHERE subject='Florence Nightingale' works perfectly in MySQL on an exact copy of the database/table, but not in SQLite3. cursor.movetoFirst() is returned as false, indicating no results are returned). Does SQLite3 encode the text in a different way or something? If I try to a query where the WHERE clause selects a int value, the query works fine and returns the expected results.
I am trying to query a table based on criteria from a join table using ORMLite.
Here is how I would express the query I am trying to write in tsql:
select * from media m inner join file f on m.fileId = f.fileId
where m.isNew = 1 OR f.isNew = 1
The result should be a list of media records where either the media record or the corresponding file record has isNew = 1.
I have read through the documentation on using OR in ORMLite, but all of the examples use a single table, not joining. Likewise I have read the documentation on joins, but none of the examples include a where clause that spans both tables. Is there any way besides a raw query to do this?
I had a look at this question: https://stackoverflow.com/a/12629645/874782 and it seems to ask the same thing, but the accepted answer produces an AND query, not an OR. Here is my code that I used to test that theory:
public List<Media> getNewMedia() {
Session session = getSession();
Account account = session.getSelectedAccount();
ContentGroup contentGroup = account.getSelectedContentGroup();
List<Media> results = null;
try {
QueryBuilder<Category, Integer> categoryQueryBuilder = getHelper().getCategoryDao().queryBuilder();
categoryQueryBuilder.where().eq("group_id", contentGroup.getId());
QueryBuilder<MediaCategory, Integer> mediaCatQb = getHelper().getMediaCategoryDao().queryBuilder();
mediaCatQb = mediaCatQb.join(categoryQueryBuilder);
QueryBuilder<FileRecord, Integer> fileQueryBuilder = getHelper().getFileDao().queryBuilder();
fileQueryBuilder.where().ge("lastUpdated", contentGroup.getLastDownload());
QueryBuilder<Media, Integer> mediaQb = getHelper().getMediaDao().queryBuilder();
mediaQb.where().eq("seen", false);
// join with the media query
results = mediaQb.join(fileQueryBuilder).join(mediaCatQb).query();
} catch (SQLException e) {
Log.e(TAG, "Sql Exception", e);
}
return results;
}
For the sake of completion, this is querying for a slightly more complex example than the one I gave above, this one expressed in tsql would be
select * from Media m join FileRecord f on m.fileRecordId = f.fileRecordId
where m.seen = false OR f.lastUpdated >= lastUpdateDate
When I run it, it is actually doing an AND query, which is what I would expect based on two joins with independent where clauses.
I think the key issue is that a where clause is inherently tied to a table, because it is performed on a QueryBuilder object which comes from a Dao that is specific to that table. How can I get around this?
I think what you are looking for is joinOr search for it in the ORMLite docs.
Like join(QueryBuilder) but this combines the WHERE statements of two
query builders with a SQL "OR".