Sqlite: create trigger programmatically - android

When my App gets installed for the first time, I create a database programmatically. Works fine so far. But when I want to add a trigger, I get an exception saying "syntax error near IF". The problem is, that I can not span the String over multiple lines in source code. So what can I do instead?
private void createTriggers(SQLiteDatabase database) {
final String triggerLocationArchived = "CREATE TRIGGER location_archived AFTER UPDATE ON location FOR EACH ROW BEGIN IF NEW.deleted <> OLD.deleted THEN UPDATE sector set sector.deleted = NEW.deleted WHERE sector.location = NEW._id; END IF; END;";
database.execSQL(triggerLocationArchived);
}
There are two tables: location and sector. Each has an INTEGER flag indicating if the row has been archived. So I want all children (sectors within a location) to be archived as well if the parent (the location) is archived.

Try this command:
CREATE TRIGGER location_archived
AFTER UPDATE ON location
FOR EACH ROW
WHEN NEW.deleted <> OLD.deleted
BEGIN
UPDATE sector
set deleted = NEW.deleted
WHERE location = NEW._id;
END
Your code will look like this:
private void createTriggers(SQLiteDatabase database) {
final String triggerLocationArchived = "CREATE TRIGGER location_archived AFTER UPDATE ON [location] FOR EACH ROW WHEN NEW.deleted <> OLD.deleted BEGIN UPDATE sector set deleted = NEW.deleted WHERE location = NEW._id; END";
database.execSQL(triggerLocationArchived);
}

Related

Maps address storing problem in arraylist

I'm working on google maps project.Users can add location and view them on the gridview.When I run my app to view all locations from database,all indexes get retrived from database successfuly and pushed arraylist.But when I try to add location.All previous locations get added database again , then my desired location added end of the array.So when I try to reach desired location from gridview,it shows me first location.I want it to be repeated just once.I think there's problem on my select query.Here's output result.
Result
GridView gridView= (GridView) findViewById(R.id.gridView);
list = new ArrayList<>();
try {
MapsActivity.database = this.openOrCreateDatabase("Places",MODE_PRIVATE,null);
Cursor cursor = MapsActivity.database.rawQuery("SELECT * FROM places",null);
int nameIx = cursor.getColumnIndex("name");
int latitudeIx = cursor.getColumnIndex("latitude");
int longitudeIx = cursor.getColumnIndex("longitude");
while (cursor.moveToNext()) {
nameFromDatabase = cursor.getString(nameIx);
String latitudeFromDatabase = cursor.getString(latitudeIx);
String longitudeFromDatabase = cursor.getString(longitudeIx);
image = cursor.getBlob(3);
// names.add(nameFromDatabase);
Double l1 = Double.parseDouble(latitudeFromDatabase);
Double l2 = Double.parseDouble(longitudeFromDatabase);
// System.out.println("coordinates:"+l1+","+l2);
locationFromDatabase = new LatLng(l1, l2);
names.add(nameFromDatabase);
locations.add(locationFromDatabase);
list.add(new Location(nameFromDatabase, image));
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
adapter = new LocationListAdapter(this, R.layout.location_items, list);
gridView.setAdapter(adapter);
I suspect that your issue is that when adding a new location, your get all the locations again from google maps.
Your code doesn't include the code for adding a location.
However, you could prevent duplicated data by defining appropriate UNIQUE constraints for your Places Database.
As an example, based upon your code, you could CREATE the table using :-
CREATE TABLE IF NOT EXISTS places (name TEXT UNIQUE ON CONFLICT IGNORE,longitude REAL,latitude REAL,image BLOB, UNIQUE (longitude,latitude) ON CONFLICT IGNORE)
Using name TEXT UNIQUE ON CONFLICT IGNORE will add a restriction/rule/constraint that the name must be unique and if an attempt is made to use a name that already exists (insert or update) then that attempt will be ignored (no error raised).
Using UNIQUE (longitude,latitude) ON CONFLICT IGNORE does the same BUT for the combination of BOTH columns.
e.g. if a row in the table has latitude 1 and longitude 1 then :-
an attempt to add a row with latitude 1 and longitude 1 will result in the attempt being ignored.
an attempt to add a row with latitude 2 and longitude 1 will work as the combination of the two values has not been used.
likewise, an attempt to add a row with latitude 1 and longitude 2 will work.

Android Kotlin Executing SQLite query in MainActivity

I'm trying to figure out how to execute a SQL query from my MainActivity. I'm currently using a large portion of this example. Upon clicking my Acknowledge button, it finds the selected rows, gets the jsonID of said row, then I'm wanting to update a value in my SQLite table of those rows.
So my question is, how do I execute my "jsonQuery" string, to my SQLite database upon clicking my Acknowledge button?
Here's the code I have in my MainActivity:
acknowledge.setOnClickListener {
var jsonData_text: String = ""
for (i in 0 until JSONParser.MrAdapter.public_modelArrayList!!.size) {
if (JSONParser.MrAdapter.public_modelArrayList!!.get(i).getSelecteds()) {
jsonData_text = jsonData_text + JSONParser.MrAdapter.public_modelArrayList!!.get(i).getJSONID() + ","
}
}
val jsonSQLQuery = jsonData_text.dropLast(1)
val jsonQuery = "update Notes set acknowledged = 1 WHERE jsonID in ("+jsonSQLQuery+")"
Log.d("logged_json", jsonQuery)
}
Thanks for any help!

Firebase database Android - check if nickname exists if not create another one until we get a new nickname

I want to create a nickname to each user who login to my app for the first time. The nickname is the user's firstname and I add a number to it from 1 to 9 000 000. For example kevin Bond could get the nickname kevin123456.
I have all the nicknames stored in a node of my firebase database. Two users shouldn't have the same nickname, so I have to check wether the nickname already exists or not in my database. If it already exists, I want to create another nickname until I get a new nickname.
I currently:
- add a listener to the usernickname node
- in onDataChange I have a for loop to create a nickname, then I check if it already exists with dataSnapshot.hasChild(newNickname). If the nickname doesn't exist I do what I want with the nickname and break the for loop, if it exists I loop the for loop to try another nickname. Here is my code:
mFirebaseDatabase.getReference().child("usernickname").orderByKey().addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (int i = 0; i < 9000000; i++) {
final Random random = new Random();
randomNumberId = random.nextInt(9000000);
String newNicknameId = mFirstnameId + String.valueOf(randomNumberId);
//if the nickname already exists we restart the for loop to get a new random number
if (dataSnapshot.hasChild(newNicknameId)) {
i++;
//else if the nickname doesn't exists we create it and stop the loop
} else if (!dataSnapshot.hasChild(newNicknameId)) {
//do what I want...
break;
}
}
}
});
My issue is that I currently have to download all the nicknames node or at least all the nicknames beginning with the user's firstname. It is an issue for me because it could cost me a lot in GB downloaded if I have a lot of users :D
I guess I could use datasnapshot.exists() to check if the nickname exists without having to download all the nicknames, but I don't see how to create another nickname if it already exists. I cannot have a for loop outside of the listener and break it inside of the listener when needed.
Do you see what is the best way to create a new nickname for my users?
Thank you,
Alex
A better approach for unique nicknames would be to append a time stamp to the name:
username + new Date().getTime();
This will add a unique long like 1493808526335 and you can be certain that two users are unlikely to register in the same millisecond with the same name.
You need to use another aproch to check if a user exists. You need to change this line:
dataSnapshot.hasChild(newNicknameId);
with
dataSnapshot.child("userName").getValue().equals(newNicknameId);
In which userName is the name of field in which you store the newNicknameId, assuming your key -> value pair looks like this: userName: "newNicknameId"
Hope it helps.
final Query query = mFirebaseDatabase.getReference().orderByChild("usernickname").equalTo("yourNewNickName");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
//here means the value exist
//do whatever you want to do
} else {
//here means the value not exist
//do whatever you want to do
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
use this will solve your problem. :)

Firebase database count number of child

I want to get first the number of children (if any). Then I want to add 1 to number of children, so the added children will be +1 from the existing.
So when I add new question, II want to add number 3. But I get it added as number 1 and it updates the existing number.
int count = 0;
public void addQuestion(View view) {
mDatabase = FirebaseDatabase.getInstance();
mRef = FirebaseDatabase.getInstance().getReference("Questions");
count = count + 1;
String nr = String.valueOf(count);
GetData getdata = new GetData(qs, A, B, C, correct);
mRef.child(nr).setValue(getdata);
Toast.makeText(AdminPanel.this, "Adding question...", Toast.LENGTH_SHORT).show();
}
You can use the push function and it will generate a unique key, so you don't have to worry about giving then unique numbers.
mRef.push();
you can also get the key that was generated if you need it,
https://firebase.google.com/docs/database/admin/save-data#getting-the-unique-key-generated-by-push
or just retrieve all the children (your questions) when needed.
I suggest you read the documentation, I found there all the information I needed.
https://firebase.google.com/docs/database/

Cursor column index changes from phone to phone

My application allows a user to call the most recent number that was called out. By hitting the "Call" button with an empty text box it will grab the latest Outgoing number in my ORM database. The issue however happens on only some phones.
When I pull my data I do so with the following code:
Dao<RecentCallsInfo, Integer> dao = null;
if (getActivity() instanceof MainActivity) {
MainActivity main = (MainActivity) getActivity();
dao = main.getDatabaseHelper().getRecentDataDao();
}
QueryBuilder<RecentCallsInfo, Integer> qb = dao.queryBuilder();
qb.orderBy(RecentCallsInfo.RECENT_COLUMN_ID, false);
qb.where().eq(RecentCallsInfo.RECENT_COLUMN_CALL_TYPE, "Outgoing");
// when you are done, prepare your query and build an iterator
CloseableIterator<RecentCallsInfo> iterator = dao.iterator(qb.prepare());
// get the raw results which can be cast under Android
AndroidDatabaseResults results = (AndroidDatabaseResults)iterator.getRawResults();
Cursor c = results.getRawCursor();
if(c.moveToFirst()){
if(!c.getString(RecentQuery.COLUMN_NUM).isEmpty()){
System.out.println("Recent Record: \n Name:" + c.getString(RecentQuery.COLUMN_NAME) +
"\nNum:" + c.getString(RecentQuery.COLUMN_NUM) + "\nNumType:" + c.getString(RecentQuery.COLUMN_NUM_TYPE)+
"\nCallType:" + c.getString(RecentQuery.COLUMN_CALL_TYPE));
etcalle.setText(c.getString(RecentQuery.COLUMN_NUM));
}
}
//RecentQuery.COLUMN_NAME = 5
//RecentQuery.COLUMN_NUM = 6
//RecentQuery.COLUMN_NUM_TYPE = 0
//RecentQuery.COLUMN_CALL_TYPE = 2
When I debug my c Cursor, it gives me these columns with these values
[recentNumberType, recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, _id]
Name:anthony
Num:(111) 111-1111
NumType:Mobile
CallType:Outgoing
When I get my c Cursor on another phone I get
[recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, recentNumberType, _id]
Name:(111) 111-1111
Num:Mobile
NumType:FREE
CallType:1867
So when I try and pull my data by index I get different values. Why does this happen? Both phones are Nexus 5 and on 4.4.2.
Any insight on this would be great. Thanks!
Columns can "change". For example, consider this case.
Version 1 of an app creates the T table, with columns A, C
In version 2, you want to change the structure of the database. So you add the B column to your "create table" scripts. In new devices, this table will have columns A, B, C.
However, in the onUpgrade() part, you just add column B (via ALTER TABLE), and the structure will end up as A, C, B.
In general it's a bad idea to use fixed ("integer") column indexes, unless you also specify which columns you want (i.e. not using SELECT *). Using getColumnIndex() (outside the loop) is safer.

Categories

Resources