use*_*531 5 sql recursion recursive-query common-table-expression mariadb
我正在尝试应用CTE和递归查询.数据库是MariaDB 10.2或更高版本.
业务规则如下:
我的架构如下(注释char用于id类型仅用于说明目的,但我将真正使用int):
CREATE TABLE IF NOT EXISTS accounts (
id CHAR(4) NOT NULL,
name VARCHAR(45) NOT NULL,
type ENUM('holding', 'portfolio') NULL,
PRIMARY KEY (id))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS holdings (
accounts_id CHAR(4) NOT NULL,
value DECIMAL(6,2) NOT NULL,
active TINYINT NOT NULL,
PRIMARY KEY (accounts_id),
CONSTRAINT fk_holdings_accounts
FOREIGN KEY (accounts_id)
REFERENCES accounts (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS portfolios (
accounts_id CHAR(4) NOT NULL,
PRIMARY KEY (accounts_id),
CONSTRAINT fk_portfolios_accounts1
FOREIGN KEY (accounts_id)
REFERENCES accounts (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS portfolios_has_accounts (
portfolios_id CHAR(4) NOT NULL,
accounts_id CHAR(4) NOT NULL,
weight DECIMAL(4,2) NOT NULL,
PRIMARY KEY (portfolios_id, accounts_id),
INDEX fk_portfolios_has_accounts_accounts1_idx (accounts_id ASC),
INDEX fk_portfolios_has_accounts_portfolios1_idx (portfolios_id ASC),
CONSTRAINT fk_portfolios_has_accounts_portfolios1
FOREIGN KEY (portfolios_id)
REFERENCES portfolios (accounts_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_portfolios_has_accounts_accounts1
FOREIGN KEY (accounts_id)
REFERENCES accounts (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)
样本数据如下:
INSERT INTO accounts(id,name,type) VALUES ('p1','portfolio1','portfolio'),('p2','portfolio2','portfolio'),('p3','portfolio3','portfolio'),('h1','holding1','holding'),('h2','holding2','holding'),('h3','holding3','holding'),('h4','holding4','holding');
INSERT INTO holdings(accounts_id,value,active) VALUES ('h1','50','1'),('h2','40','0'),('h3','70','1'),('h4','40','1');
INSERT INTO portfolios(accounts_id) VALUES ('p1'),('p2'),('p3');
INSERT INTO portfolios_has_accounts(portfolios_id,accounts_id,weight) VALUES ('p1','h1','1'),('p1','p2','0.5'),('p2','h2','2'),('p2','p3','1'),('p3','h3','2'),('p3','h4','0.5');
Run Code Online (Sandbox Code Playgroud)
账户
id name type
p1 portfolio1 portfolio
p2 portfolio2 portfolio
p3 portfolio3 portfolio
h1 holding1 holding
h2 holding2 holding
h3 holding3 holding
h4 holding4 holding
Run Code Online (Sandbox Code Playgroud)
投资组合
portfolios_id
p1
p2
p3
Run Code Online (Sandbox Code Playgroud)
增持
id value active
h1 50 1
h2 40 0
h3 70 1
h4 40 1
Run Code Online (Sandbox Code Playgroud)
portfolios_has_accounts
portfolios_id accounts_id weight
p1 h1 1
p1 p2 0.5
p2 h2 2
p2 p3 1
p3 h3 2
p3 h4 0.5
Run Code Online (Sandbox Code Playgroud)
我的目标是找到:
查找仅包含有效馆藏的所有帐户.给定样本数据,它是p3,h1,h3和h4.不包括p2,因为它包括不活跃的h2,并且因为它包括p2而不包括p1.
投资组合p1的总价值.给出样本数据,它是170:1*50 + 0.5*(2*40 + 1*(2*70 + 0.5*40))
持有量乘以的常数导致投资组合p1的总价值.给出样本数据,它们如下(注意1*h1 + 1*h2 + 1*h3 + 0.25*h4 = 170)
.
id weight
h1 1
h2 1
h3 1
h4 .25
Run Code Online (Sandbox Code Playgroud)
我怎么能做到这一点?
请评论这些是否应该以不同的方式进行,或者从性能的角度来看,它们是否有任何重大问题?
目标#1
MariaDB [recursion]> WITH RECURSIVE t AS (
-> SELECT accounts_id FROM holdings WHERE active=0
-> UNION ALL
-> SELECT pha.portfolios_id
-> FROM portfolios_has_accounts pha
-> INNER JOIN t ON t.accounts_id=pha.accounts_id
-> )
-> SELECT a.* FROM accounts a
-> LEFT OUTER JOIN t ON t.accounts_id=a.id
-> WHERE t.accounts_id IS NULL;
+----+------------+-----------+
| id | name | type |
+----+------------+-----------+
| h1 | holding1 | holding |
| h3 | holding3 | holding |
| h4 | holding4 | holding |
| p3 | portfolio3 | portfolio |
+----+------------+-----------+
4 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
目标#2
MariaDB [recursion]> WITH RECURSIVE t AS (
-> SELECT pha.*, h.value
-> FROM portfolios_has_accounts pha
-> LEFT OUTER JOIN holdings h ON h.accounts_id=pha.accounts_id
-> WHERE pha.portfolios_id="p1"
-> UNION ALL
-> SELECT pha.portfolios_id, pha.accounts_id, pha.weight*t.weight, h.value
-> FROM t
-> INNER JOIN portfolios_has_accounts pha ON pha.portfolios_id=t.accounts_id
-> LEFT OUTER JOIN holdings h ON h.accounts_id=pha.accounts_id
-> )
-> SELECT SUM(weight*value) FROM t WHERE value IS NOT NULL;
+-------------------+
| SUM(weight*value) |
+-------------------+
| 170.0000 |
+-------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
目标#3
MariaDB [recursion]> WITH RECURSIVE t AS (
-> SELECT pha.*, h.value
-> FROM portfolios_has_accounts pha
-> LEFT OUTER JOIN holdings h ON h.accounts_id=pha.accounts_id
-> WHERE pha.portfolios_id="p1"
-> UNION ALL
-> SELECT pha.portfolios_id, pha.accounts_id, pha.weight*t.weight, h.value
-> FROM t
-> INNER JOIN portfolios_has_accounts pha ON pha.portfolios_id=t.accounts_id
-> LEFT OUTER JOIN holdings h ON h.accounts_id=pha.accounts_id
-> )
-> SELECT accounts_id, weight FROM t WHERE value IS NOT NULL;
+-------------+--------+
| accounts_id | weight |
+-------------+--------+
| h1 | 1.00 |
| h2 | 1.00 |
| h3 | 1.00 |
| h4 | 0.25 |
+-------------+--------+
4 rows in set (0.01 sec)
MariaDB [recursion]>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |