sqlite select query with foreign key for another table - android

I am working on a project with xamarin android using the sqlite.net library. I have a select query that will execute and create a collection of custom objects called worker :
var command = conn.CreateCommand("SELECT * FROM tblWorkers");
var results = command.ExecuteQuery<Worker>();
ObservableCollection<Worker> workers = new ObservableCollection<Worker>(results);
return workers;
One of the columns is a foreign key and I need to get a value from that table just wondering what the best way to do that is. The foreign key on the data table tblWorkers is TitleID On that table is a varchar(datatable : tblTitles column : Title - nvarchar) I need to retrieve just wondering what the best way to do that is?

var command = conn.CreateCommand("SELECT * FROM tblWorkers LEFT JOIN tblTitles ON tblWorkers.TitleID = tblTitles.id");
Now, the above will work, but in general you'll want to avoid SELECT * usage. Only get the fields you want. Ideally, something like this...
var command = conn.CreateCommand("SELECT tblWorkers.SomeFieldYouWant, tblWorkers.SomeOtherFieldYouWant, ... , tblTitles.Title FROM tblWorkers LEFT JOIN tblTitles ON tblWorkers.TitleID = tblTitles.id");

Related

Android SQLite additional WHERE condition after MATCH

In Android SQLite i got tabel like this
domainObjectId: String // like '9876543210'
name: String
description: String
I want to use FTS on this to search without worrying about diacritical marks, how ever i want to let user select also by typing part of object ID(ex. last 4 char)
I got select like
`SELECT * FROM tabel LEFT JOIN tabel_fts on tabel_fts.domainObjectId = tabel.domainObjectId WHERE tabel_fts MATCH '3210*' OR tabel.domainObjectId LIKE '%3210%'
But in return i get error
unable to use function MATCH in the requested context (code 1 SQLITE_ERROR);
Is this possible to add additional condition to select with MATCH?
Try to remove "MATCH" into separate "SELECT":
`SELECT * FROM tabel LEFT JOIN (select * from tabel_fts WHERE tabel_fts.domainObjectId MATCH '3210*') as tabel_fts WHERE tabel.domainObjectId LIKE '%3210%' OR table_fts.ID IS NOT NULL
By the way:
In your "WHERE tabel_fts" it seemed you've missed a column name
There is no "ON" condition in tables JOINm just "WHERE". That's OK? May be it would be better to use UNION?

compileStatement throws Exception [duplicate]

Question: Is it possible to use a variable as your table name without having to use string constructors to do so?
Info:
I'm working on a project right now that catalogs data from a star simulation of mine. To do so I'm loading all the data into a sqlite database. It's working pretty well, but I've decided to add a lot more flexibility, efficiency, and usability to my db. I plan on later adding planetoids to the simulation, and wanted to have a table for each star. This way I wouldn't have to query a table of 20m some planetoids for the 1-4k in each solar system.
I've been told using string constructors is bad because it leaves me vulnerable to a SQL injection attack. While that isn't a big deal here as I'm the only person with access to these dbs, I would like to follow best practices. And also this way if I do a project with a similar situation where it is open to the public, I know what to do.
Currently I'm doing this:
cursor.execute("CREATE TABLE StarFrame"+self.name+" (etc etc)")
This works, but I would like to do something more like:
cursor.execute("CREATE TABLE StarFrame(?) (etc etc)",self.name)
though I understand that this would probably be impossible. though I would settle for something like
cursor.execute("CREATE TABLE (?) (etc etc)",self.name)
If this is not at all possible, I'll accept that answer, but if anyone knows a way to do this, do tell. :)
I'm coding in python.
Unfortunately, tables can't be the target of parameter substitution (I didn't find any definitive source, but I have seen it on a few web forums).
If you are worried about injection (you probably should be), you can write a function that cleans the string before passing it. Since you are looking for just a table name, you should be safe just accepting alphanumerics, stripping out all punctuation, such as )(][;, and whitespace. Basically, just keep A-Z a-z 0-9.
def scrub(table_name):
return ''.join( chr for chr in table_name if chr.isalnum() )
scrub('); drop tables --') # returns 'droptables'
For people searching for a way to make the table as a variable, I got this from another reply to same question here:
It said the following and it works. It's all quoted from mhawke:
You can't use parameter substitution for the table name. You need to add the table name to the query string yourself. Something like this:
query = 'SELECT * FROM {}'.format(table)
c.execute(query)
One thing to be mindful of is the source of the value for the table name. If that comes from an untrusted source, e.g. a user, then you need to validate the table name to avoid potential SQL injection attacks. One way might be to construct a parameterised query that looks up the table name from the DB catalogue:
import sqlite3
def exists_table(db, name):
query = "SELECT 1 FROM sqlite_master WHERE type='table' and name = ?"
return db.execute(query, (name,)).fetchone() is not None
I wouldn't separate the data into more than one table. If you create an index on the star column, you won't have any problem efficiently accessing the data.
Try with string formatting:
sql_cmd = '''CREATE TABLE {}(id, column1, column2, column2)'''.format(
'table_name')
db.execute(sql_cmd)
Replace 'table_name' with your desire.
To avoid hard-coding table names, I've used:
table = "sometable"
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS {} (
importantdate DATE,
somename VARCHAR,
)'''.format(table))
c.execute('''INSERT INTO {} VALUES (?, ?)'''.format(table),
(datetime.strftime(datetime.today(), "%Y-%m-%d"),
myname))
As has been said in the other answers, "tables can't be the target of parameter substitution" but if you find yourself in a bind where you have no option, here is a method of testing if the table name supplied is valid.
Note: I have made the table name a real pig in an attempt to cover all of the bases.
import sys
import sqlite3
def delim(s):
delims="\"'`"
use_delim = []
for d in delims:
if d not in s:
use_delim.append(d)
return use_delim
db_name = "some.db"
db = sqlite3.connect(db_name)
mycursor = db.cursor()
table = 'so""m ][ `etable'
delimiters = delim(table)
if len(delimiters) < 1:
print "The name of the database will not allow this!"
sys.exit()
use_delimiter = delimiters[0]
print "Using delimiter ", use_delimiter
mycursor.execute('SELECT name FROM sqlite_master where (name = ?)', [table])
row = mycursor.fetchall()
valid_table = False
if row:
print (table,"table name verified")
valid_table = True
else:
print (table,"Table name not in database", db_name)
if valid_table:
try:
mycursor.execute('insert into ' +use_delimiter+ table +use_delimiter+ ' (my_data,my_column_name) values (?,?) ',(1,"Name"));
db.commit()
except Exception as e:
print "Error:", str(e)
try:
mycursor.execute('UPDATE ' +use_delimiter+ table +use_delimiter+ ' set my_column_name = ? where my_data = ?', ["ReNamed",1])
db.commit()
except Exception as e:
print "Error:", str(e)
db.close()
you can use something like this
conn = sqlite3.connect()
createTable = '''CREATE TABLE %s (# );''' %dateNow)
conn.execute(createTable)
basically, if we want to separate the data into several tables according to the date right now, for example, you want to monitor a system based on the date.
createTable = '''CREATE TABLE %s (# );''' %dateNow) means that you create a table with variable dateNow which according to your coding language, you can define dateNow as a variable to retrieve the current date from your coding language.
You can save your query in a .sql or txt file and use the open().replace() method to use variables in any part of your query. Long time reader but first time poster so I apologize if anything is off here.
```SQL in yoursql.sql```
Sel *
From yourdbschema.tablenm
```SQL to run```
tablenm = 'yourtablename'
cur = connect.cursor()
query = cur.execute(open(file = yoursql.sql).read().replace('tablenm',tablenm))
You can pass a string as the SQL command:
import sqlite3
conn = sqlite3.connect('db.db')
c = conn.cursor()
tablename, field_data = 'some_table','some_data'
query = 'SELECT * FROM '+tablename+' WHERE column1=\"'+field_data+"\""
c.execute(query)

Sort in GreenDAO

Raw query:
SELECT * FROM SAVED_JOB2 S, JOB J WHERE J._id=S._id ORDER BY DATE_SAVED DESC
How can I achieve sort for column in JOIN table. I have tried:
QueryBuilder<Job> queryBuilder = daoSession.queryBuilder(Job.class);
queryBuilder.join(JobDao.Properties.Id, SavedJob2.class, SavedJob2Dao.Properties.Id);
List<Job> list = queryBuilder1.list();
This normal JOIN works perfect. But I need to sort for date_saved column in table SavedJob.
I tried to add this line:
queryBuilder.orderDesc(SavedJob2Dao.Properties.date_saved);
But this line returns this error:
Property 'date_saved' is not part of com.xxx.xxx.db.JobDao
Table JobDao:
id (PK)
title
description
requirements
allowance
type
status
Table SavedJobDao:
id (PK autoincrement)
j_id (FK to JabDao)
date_saved
status
You don't need to do any JOIN with greenDao. It works with objects, so in your savedJob you should have an object Job instead job_id.
So you can order by date_saved, but searching in savedJob only, you don't need either JOIN.
There are a lot of examples. And the official doc is awesome!.

SQLite Left Outer Join not working as expected in Android

I have prepared a left outer join query that should be returning non-null data when a record exists in my BLOB table that matches keys with a record in my INCIDENT table.
Essentially, the data and query looks like this:
Table A
Key
Table B
Key
Blob
and the query I'm running, should show all records from A, and the 'hasb' column should be 1 if there's a record in B with a matching key column, or 0 if there isn't. So the query should look like this:
SELECT A.*, ifnull(A.Key = B.Key, 0) as hasb FROM A
LEFT OUTER JOIN B ON A.Key = B.Key
Ok, so my problem is, this query seems to work everywhere I try to use it EXCEPT on the Android device.
Here's a SQLFiddle with the actual tables and query in question. Note that the query works there.
http://sqlfiddle.com/#!7/89e7d/4
Anyone know why this doesn't work on Android? The device I'm testing with is a Samsung Galaxy S 3 running Android 4.1.1.
I think you're overcomplicating things with the ifnull.
This is the query in your fiddle:
SELECT ifnull( a.userid = b.userid, 0 ) FROM incidentdata AS a
LEFT OUTER JOIN incidentblob AS b
ON ( a.userid = b.userid ) AND ( a.incidenttag = b.incidenttag );
This is the query I would write:
SELECT a.userid, a.incidenttag, b._id, b._id is not null hasb
FROM incidentdata AS a
LEFT JOIN incidentblob AS b
ON a.userid = b.userid AND a.incidenttag = b.incidenttag
Does it work? If it doesn't please, provide the SQLite version you're using. Anyway, I'm pretty sure the issue resides in the following items:
Understanding that null = null does not return TRUE but rather null
null values being present in both b.userid as well as a.incidenttag after performing the left join
I know your query "seems to work everywhere".
However, I suggest you an alternative one:
SELECT a.*, b.ROWID IS NOT NULL AS hasb FROM a LEFT JOIN b ON a.key IS b.key;
Differences:
Avoid IFNULL function call;
a.key IS b.key will handle a null key value;
checking b.ROWID is b row data independent.

Ormlite inner join on three tables

i want to create an inner join on three tables like this one for example:
SELECT C.Description, D.ItemDescription
FROM OrderDetailStatement AS D
INNER JOIN OrderHeaderStatement AS H
ON H.OrderHeaderStatementRefID = D.OrderHeaderStatementRefID
INNER JOIN customers AS C
ON H.CustomerRefID = C.CustomerRefID
WHERE (D.MixedValue > 1000)
but i'm a little bit confused, could you please provide me a walkthrough?
thanks in advance
ORMLite now supports simple JOIN statements. You can do something like the following:
// start the order header query
QueryBuilder<OrderHeader, Integer> orderHeaderQb = orderHeaderDao.queryBuilder();
QueryBuilder<Customer, Integer> customerQb = customerDao.queryBuilder();
// join with the order query
orderHeaderQb.join(customerQb);
// start the order statement query
QueryBuilder<OrderStatement, Integer> orderStatementQb =
orderStatementDao.queryBuilder();
orderStatementQb.where().gt("mixedvalue", 100);
// join with the order-header query
orderStatementQb.join(orderHeaderQb);
List<OrderStatement> orderStatementQb.query();
Notice, however, that you can only get entities from the query builder using this mechanism. If you want to get your two description fields from different objects then you would have to still use a raw-query.
There is support for "raw queries" including the Dao.queryRaw() method where you can use your own SQL. I suspect you've found them already. Here are the docs for raw queries.

Categories

Resources