/* functions.mysql Some functions for use with a KMyMoney MySql database. Load them into your database with command: mysql KMyMoney < this_file To preserve them in backups, remember to add the -R flag to mysqldump. */ delimiter // DROP FUNCTION IF EXISTS toDecimal// CREATE FUNCTION toDecimal(mymoneymoney VARCHAR(32)) RETURNS DECIMAL(12,6) READS SQL DATA BEGIN /* Converts a MyMoneyMoney numerator/denominator string to a decimal number */ DECLARE result DECIMAL (12,6); SELECT SUBSTRING_INDEX(mymoneymoney, '/', 1) / SUBSTRING_INDEX(mymoneymoney, '/', -1) INTO result; RETURN result; END // delimiter ; delimiter // DROP FUNCTION IF EXISTS cashBalance// CREATE FUNCTION cashBalance(acctId VARCHAR(32)) RETURNS DECIMAL(12,2) READS SQL DATA BEGIN /* Returns the cash balance as of today of an account specified by internal id.*/ /* to determine id - SELECT id FROM kmmAccounts WHERE accountName = 'whatever'; Sample usage - SELECT cashBalance('A000001'); */ DECLARE result DECIMAL (12,2); SELECT SUM(toDecimal(shares)) INTO result FROM kmmSplits WHERE accountId = acctId AND postDate <= NOW() AND txType = 'N'; RETURN result; END // delimiter ; delimiter // DROP PROCEDURE IF EXISTS listBalances// CREATE PROCEDURE listBalances(IN parent varchar(32)) READS SQL DATA BEGIN /* Lists the balances of all accounts subsidiary to a named account. NOTE: not recursive Sample usage: - CALL listBalances('Asset'); */ SELECT accountName, cashBalance(id) FROM kmmAccounts where parentId = (SELECT id from kmmAccounts WHERE accountName = parent) ORDER by 1; END // delimiter ; delimiter // DROP FUNCTION IF EXISTS latestPrice// CREATE FUNCTION latestPrice(secId VARCHAR(32)) RETURNS DECIMAL(12,6) READS SQL DATA BEGIN /* Returns the latest price for a security identified by internal id. */ /* to determine id - SELECT id FROM kmmSecurities WHERE name = 'whatever'; */ DECLARE result DECIMAL (12,6); SELECT toDecimal(price) INTO result FROM kmmPrices WHERE fromId = secId AND priceDate = (SELECT MAX(priceDate) FROM kmmPrices WHERE fromId = secId); RETURN result; END // delimiter ; delimiter // DROP FUNCTION IF EXISTS shareBalance// CREATE FUNCTION shareBalance(acctId VARCHAR(32)) RETURNS DECIMAL(12,6) READS SQL DATA BEGIN /* Returns the share balance for an Stock account identified by internal id. NOTE: similar to cashBalance but with greater precision */ DECLARE result DECIMAL (12,6); SELECT SUM(toDecimal(shares)) INTO result FROM kmmSplits WHERE accountId = acctId AND txType = 'N'; RETURN result; END // delimiter ; delimiter // DROP FUNCTION IF EXISTS valuation// CREATE FUNCTION valuation(acctId VARCHAR(32)) RETURNS DECIMAL(12,2) READS SQL DATA BEGIN /* Returns the current value of a Stock account identified by internal id */ DECLARE result DECIMAL(12,2); DECLARE secId VARCHAR(32); SELECT currencyId FROM kmmAccounts WHERE id = acctId INTO secId; SELECT shareBalance(acctId) * latestPrice(secId) INTO result; RETURN result; END // delimiter ; delimiter // DROP PROCEDURE IF EXISTS listValues// CREATE PROCEDURE listValues(IN parent varchar(32)) READS SQL DATA BEGIN /* Lists the current values of all stocks subsidiary to a named Investment account. NOTE: not recursive */ SELECT parent AS 'Portfolio'; SELECT accountName, valuation(id) AS 'Value' FROM kmmAccounts where parentId = (SELECT id from kmmAccounts WHERE accountName = parent) ORDER by 1; SELECT SUM(valuation(id)) AS 'Total Value' FROM kmmAccounts where parentId = (SELECT id from kmmAccounts WHERE accountName = parent); END // delimiter ; delimiter // DROP FUNCTION IF EXISTS payeeName// CREATE FUNCTION payeeName(payeeId VARCHAR(32)) RETURNS MEDIUMTEXT READS SQL DATA BEGIN /* Returns payee name from id, with NULL test */ DECLARE result MEDIUMTEXT; IF payeeId IS NULL THEN SET result = 'Empty Payee'; ELSE SELECT name FROM kmmPayees WHERE id = payeeId INTO result; END IF; RETURN result; END // delimiter ; delimiter // DROP FUNCTION IF EXISTS categoryName// CREATE FUNCTION categoryName(categoryId VARCHAR(32)) RETURNS MEDIUMTEXT READS SQL DATA BEGIN /* Returns fully qualified category name from its id */ DECLARE result MEDIUMTEXT; DECLARE thisName MEDIUMTEXT; DECLARE parent VARCHAR(32); IF categoryId IS NULL THEN RETURN 'Empty Category'; END IF; SELECT accountName from kmmAccounts WHERE id = categoryId INTO result; SELECT parentId from kmmAccounts WHERE id = categoryId INTO parent; WHILE parent IS NOT NULL DO SELECT accountName from kmmAccounts WHERE id = parent INTO thisName; SET result = CONCAT(thisName, ':', result); SELECT parentId from kmmAccounts WHERE id = parent INTO parent; END WHILE; RETURN result; END // delimiter ; /* some useful functions re tax */ DROP VIEW IF EXISTS taxCats; CREATE VIEW taxCats AS SELECT kvpId AS accountId FROM kmmKeyValuePairs WHERE kvpKey = 'Tax' AND kvpData = 'Yes'; DROP VIEW IF EXISTS taxSplits; CREATE VIEW taxSplits AS SELECT accountId, payeeId, postDate, CAST(toDecimal(value) AS decimal(12,2)) AS Amount FROM kmmSplits WHERE txType = 'N' AND accountId IN (SELECT * FROM taxCats); /* Sample: generate a tax report for UK yesr 08-09. Sorted by payee within Category */ DROP VIEW IF EXISTS taxReport; CREATE VIEW taxReport AS SELECT categoryName(accountId) AS Account, payeeName(payeeId) As Payee, DATE_FORMAT(postDate, '%d/%m/%y') As Date, ABS(Amount) AS Amount FROM taxSplits WHERE postDate > "2008-04-05" and postDate < "2009-04-06" ORDER BY 1, 2, 3;