您可以通过不使用联接而是通过访问各个对象以及查询来获取某个时间点的余额来实现这一点(假设您想要一个运行平衡)。
所以你可以有以下道的
@Query("SELECT * FROM transactions WHERE transaction_account_id = :accountID")
List<TransactionEntity> getTransactionsForAnAccount(long accountID);
@Query("SELECT * FROM accounts WHERE account_id = :accountId LIMIT 1")
Accounts getAccountById(long accountId);
@Query("SELECT sum(transaction_value) FROM transactions WHERE transaction_date <= :transactionDate AND transaction_account_id = :accountId ORDER BY transaction_date ASC")
Double getBalanaceAtADate(long accountId, String transactionDate);
第一个返回帐户的交易。
第二个根据它的 id 返回一个帐户。
第三个将返回所提供日期的所有交易的总和以及所有以前的交易(因此是运行余额)。
示例
您可以使用类似以下的内容(不是在 Java 中,而是在 Kotlin 中):-
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDB = Room.databaseBuilder(this,Database.class,Database.DBNAME)
.allowMainThreadQueries()
.build();
mDBDao = mDB.getAADao();
mDBDao.addAccount(new Accounts("Account1",0));
mDBDao.addAccount(new Accounts("Account2"));
mDBDao.addTransaction(new TransactionEntity("Buy my first thing","2019-09-20 10:20",-25.46,"blah",0,1,0));
mDBDao.addTransaction(new TransactionEntity("Buy my second thing","2019-09-20 11:30",-65.30,"blah",0,1,0));
mDBDao.addTransaction(new TransactionEntity("Deposit","2019-09-21 12:00",100,"blah",1,1,0));
mDBDao.addTransaction(new TransactionEntity("Deposit 1","2019-09-22 13:00",50,"blah",1,2,0));
mDBDao.addTransaction(new TransactionEntity("Deposit 2","2019-09-22 14:00",150,"blah",1,2,0));
//<<<<<<<<< previous code is initialisation and setting up some testing data >>>>>>>
List<TransactionEntity> tlaccount1 = mDBDao.getTransactionsForAnAccount(1); //<<<<<<<< get the transactions
logTransactions(tlaccount1); //<<<<<<<<<< invokes the logTransactions method as below
}
private void logTransactions(List<TransactionEntity> tl) {
final String TAG = "TRANSLOG";
// If no transactions the return after logging message
if (tl.size() < 1) {
Log.d("TRANSLOG","No transactions to process");
return;
}
// First get the Account from the first Transaction
Accounts currentAccount = mDBDao.getAccountById(tl.get(0).getAccountId());
// Iterate through the transactions
for (TransactionEntity tle: tl) {
double running_balance = mDBDao.getBalanaceAtADate(currentAccount.accountid,tle.getDate()); //<<<<<<<<<< GET the running balance
// Output the current transaction with the account name and balance
Log.d(TAG,
"Account Name: " + currentAccount.getName() +
" Title: " + tle.getTitle() +
" Value: " + tle.getValue().toString() +
" Balance: " + running_balance
);
}
}
结果
2019-09-23 10:59:19.225 D/TRANSLOG: Account Name: Account1 Title: Buy my first thing Value: -25.46 Balance: -25.46
2019-09-23 10:59:19.228 D/TRANSLOG: Account Name: Account1 Title: Buy my second thing Value: -65.3 Balance: -90.75999999999999
2019-09-23 10:59:19.230 D/TRANSLOG: Account Name: Account1 Title: Deposit Value: 100.0 Balance: 9.240000000000009
所以没有余额 25.46 被提取,然后 65.30 被提取(-90.76),最后 100 被存入,因此最后一个余额是 -90.76 + 100 = 9.24。
- 请注意,这可能不是最有效的方法,但相对容易编码和理解。
附加
要真正连接表并从其他表中获取数据,您需要另一个类,以便您可以拥有一个具有所需成员变量的对象。
例如,要将两个表与相关数据合并,您可以使用如下类:-
public class TransactionWithAccountAndDerivedBalance {
long transactionId;
String transactionTitle;
String transactionDate;
double transactionValue;
String transactionNotes;
int transactionType;
long accountId;
long budgetId;
String accountName;
double balance;
public long getTransactionId() {
return transactionId;
}
public void setTransactionId(long transactionId) {
this.transactionId = transactionId;
}
public String getTransactionTitle() {
return transactionTitle;
}
public void setTransactionTitle(String transactionTitle) {
this.transactionTitle = transactionTitle;
}
public String getTransactionDate() {
return transactionDate;
}
public void setTransactionDate(String transactionDate) {
this.transactionDate = transactionDate;
}
public double getTransactionValue() {
return transactionValue;
}
public void setTransactionValue(double transactionValue) {
this.transactionValue = transactionValue;
}
public String getTransactionNotes() {
return transactionNotes;
}
public void setTransactionNotes(String transactionNotes) {
this.transactionNotes = transactionNotes;
}
public int getTransactionType() {
return transactionType;
}
public void setTransactionType(int transactionType) {
this.transactionType = transactionType;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public long getBudgetId() {
return budgetId;
}
public void setBudgetId(long budgetId) {
this.budgetId = budgetId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
还有一条道:-
@Query("SELECT " +
"transaction_id AS transactionId, " +
"transaction_title AS transactionTitle, " +
"transaction_date AS transactionDate, " +
"transaction_value AS transactionValue, " +
"transaction_notes AS transactionNotes, " +
"transaction_type AS transactionType, " +
"transaction_account_id AS accountId, " +
"transaction_budget_id AS budgetId, " +
"account_name As accountName, " +
"(SELECT sum(transaction_value) FROM transactions WHERE transaction_date <= '2019-09-20 12:00') AS balance" +
" FROM transactions JOIN accounts ON transaction_account_id = account_id " +
" WHERE account_id = :accountId")
List<TransactionWithAccountAndDerivedBalance> getFullTransaction(long accountId);
- 备注
- TransactionWithAccountAndDerivedBalance 类中使用的变量名与列名不同,因此需要指定结果集中的列名(即
table_column_name AS class_member_variable_name)。
- 这还包括在子查询中使用 sum 函数的列。请注意,这将始终返回与硬编码日期的选择标准相同的值(为了简单/演示)。
最后加法
上一个查询似乎就是您所要求的(尽管所有帐户的交易都会被求和)。但是,您可能需要一个流动的平衡。
TransactionWithAccountAndDerivedBalance 无需更改即可使用。
对于流动余额(因此以前的方法不关心帐户),您需要能够区分子查询的列名(使用 transaction_date <= transaction_date 将返回每笔交易,因为值始终是相同(就像检查 accountId 一样))。
这可以通过设置主查询的名称并使用该名称作为前缀来引用列来完成。
Dao 可以是(使用 main 作为主查询的名称):-
@Query("SELECT " +
"main.transaction_id AS transactionId, " +
"main.transaction_title AS transactionTitle, " +
"main.transaction_date AS transactionDate, " +
"main.transaction_value AS transactionValue, " +
"main.transaction_notes AS transactionNotes, " +
"main.transaction_type AS transactionType, " +
"main.transaction_account_id AS accountId, " +
"main.transaction_budget_id AS budgetId, " +
"account_name As accountName, " +
/* The SubQuery to get the balanace for the current transaction */
"(" +
"SELECT sum(transaction_value) " +
"FROM transactions " +
"WHERE transaction_date <= main.transaction_date " +
"AND main.transaction_account_id = transaction_account_id" +
") AS balance" +
/* Back to the Main Query */
" FROM transactions AS main JOIN accounts ON transaction_account_id = account_id " +
" WHERE account_id = :accountId")
List<TransactionWithAccountAndDerivedBalance> getFullTransaction(long accountId);
这将返回与答案的初始部分相同的结果。
例如,使用:-
logOtherWay(mDBDao.getFullTransaction(1));
logOtherWay 方法在哪里:-
private void logOtherWay(List<TransactionWithAccountAndDerivedBalance> twaadbList) {
for (TransactionWithAccountAndDerivedBalance twaadb: twaadbList) {
Log.d("TRANSOTHER","Account Name :" + twaadb.getAccountName() +
" Title: " + twaadb.getTransactionTitle() +
" Value " + twaadb.getTransactionValue() +
" Balance: " + twaadb.getBalance()
);
}
}
最终结果
结果(连同初始方式的结果)将是:-
09-23 15:18:00.868 4079-4079/? D/TRANSLOG: Account Name: Account1 Title: Buy my first thing Value: -25.46 Balance: -25.46
09-23 15:18:00.868 4079-4079/? D/TRANSLOG: Account Name: Account1 Title: Buy my second thing Value: -65.3 Balance: -90.75999999999999
09-23 15:18:00.868 4079-4079/? D/TRANSLOG: Account Name: Account1 Title: Deposit Value: 100.0 Balance: 9.240000000000009
09-23 15:18:00.868 4079-4079/? D/TRANSOTHER: Account Name :Account1 Title: Buy my first thing Value -25.46 Balance: -25.46
09-23 15:18:00.868 4079-4079/? D/TRANSOTHER: Account Name :Account1 Title: Buy my second thing Value -65.3 Balance: -90.75999999999999
09-23 15:18:00.868 4079-4079/? D/TRANSOTHER: Account Name :Account1 Title: Deposit Value 100.0 Balance: 9.240000000000009