如何从另一个表中求和

时间:2019-09-22 21:47:18

标签: android sqlite android-sqlite android-room

我有一个带有帐户的表,另一个带有事务的表:

@Parcelize
@Entity(tableName = Database.Accounts.TABLE_NAME)
data class Account(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = Database.Accounts.COL_ID) val id: Long = 0,
    @ColumnInfo(name = Database.Accounts.COL_NAME) val name: String = "",
    @ColumnInfo(name = Database.Accounts.COL_BALANCE) val balance: Double = 0.0
) : Model

每笔交易都属于一个帐户,因此拥有一个account_id

data class TransactionEntity(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = Database.Transactions.COL_ID) val id: Long = 0L,
    @ColumnInfo(name = Database.Transactions.COL_TITLE) val title: String = "",
    @ColumnInfo(name = Database.Transactions.COL_DATE) val date: LocalDate = LocalDate.MIN,
    @ColumnInfo(name = Database.Transactions.COL_VALUE) val value: Double = 0.0,
    @ColumnInfo(name = Database.Transactions.COL_NOTES) val notes: String = "",
    @ColumnInfo(name = Database.Transactions.COL_TYPE) @TransactionType val type: Int = TransactionType.EARNING,
    @ColumnInfo(name = Database.Transactions.COL_ACCOUNT_ID) val accountId: Long = Account.DEFAULT_ACCOUNT_ID,
    @ColumnInfo(name = Database.Transactions.COL_BUDGET_ID) val budgetId: Long? = null
) : Model

查询帐户时,balance应该是该帐户所有交易的总和value

我怎么能意识到这一点?

2 个答案:

答案 0 :(得分:1)

您可以通过不使用联接,而是通过访问各个对象以及查询以在某个时间点获取余额来实现此目的(假设您想要保持平衡)。

因此,您可以使用以下Dao's

@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;
    }
}

和一个Dao沿着:-

@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

答案 1 :(得分:-1)

我使用AccountWithBalance POJO实现了它:

this.$route.params.slug

以及以下查询:

@Parcelize
@Entity(tableName = Database.Accounts.TABLE_NAME)
data class AccountWithBalance(
    @Embedded val account: Account = Account(),
    @ColumnInfo(name = Database.Accounts.COL_BALANCE) val balance: Double = 0.0
) : Model {

    val id: Long
        get() = account.id

    val name: String
        get() = account.name
}