我正在使用join运行以下查询。但是这个联接并没有给出正确的结果
SELECT pr.start_date,pr.end_date, p.contribution_id
FROM civicrm_membershipperiod pr
INNER JOIN civicrm_membership_payment p ON pr.membership_id=p.membership_id
where p.membership_id=11
两个表都包含三个记录
mysql> select * FROM `civicrm_membershipperiod` ;
+----+---------------+------------+------------+
| id | membership_id | start_date | end_date |
+----+---------------+------------+------------+
| 1 | 11 | 2015-01-01 | 2015-12-31 |
| 2 | 11 | 2017-07-09 | 2018-07-08 |
| 3 | 11 | 2018-07-09 | 2019-07-08 |
+----+---------------+------------+------------+
3 rows in set (0.00 sec)
--------------------------------------------------------------------------
mysql> select * FROM `civicrm_membership_payment` ;
+----+---------------+-----------------+
| id | membership_id | contribution_id |
+----+---------------+-----------------+
| 27 | 11 | 39 |
| 28 | 11 | 40 |
| 29 | 11 | 41 |
+----+---------------+-----------------+
3 rows in set (0.00 sec)
但结果是九条记录而不是三条记录。
mysql> SELECT pr.start_date,pr.end_date, p.contribution_id FROM civicrm_membershipperiod pr INNER JOIN civicrm_membership_payment p ON pr.membership_id=p.membership_id where p.membership_id=11;
+------------+------------+-----------------+
| start_date | end_date | contribution_id |
+------------+------------+-----------------+
| 2015-01-01 | 2015-12-31 | 39 |
| 2015-01-01 | 2015-12-31 | 40 |
| 2015-01-01 | 2015-12-31 | 41 |
| 2017-07-09 | 2018-07-08 | 39 |
| 2017-07-09 | 2018-07-08 | 40 |
| 2017-07-09 | 2018-07-08 | 41 |
| 2018-07-09 | 2019-07-08 | 39 |
| 2018-07-09 | 2019-07-08 | 40 |
| 2018-07-09 | 2019-07-08 | 41 |
+------------+------------+-----------------+
9 rows in set (0.00 sec)
我不确定错误在哪里。
这是我想要的:
2015-01-01 2015-12-31 39
2017-07-09 2018-07-08 40
2018-07-09 2019-07-08 41
答案 0 :(得分:0)
在这种情况下,我希望看到9条记录。这是因为第一个表中的membership_id为11的记录有三个,第二个表中的membership的三个记录为11个,3 * 3 = 9,即第一个表中membership_id为11的每一行都与membership_id的每一行连接第二个表中的11个。
这里的问题是这两个表之间存在多对多的关系,因此您需要一个联结。但是,你真的需要:civicrm_membership_payment表吗?你能将contrib_id从civicrm_membership_payment移到civicrm_membershipperiod,然后删除civicrm_membership_payment吗?然后就做:
select * from civicrm_membershipperiod
如果你不能这样做,那么我会查看Junction Tables中的多对多关系。
答案 1 :(得分:0)
根据您所写的内容,结果绝对正确。 两个表civicrm_membershipperiod和civicrm_membership_payment中每个元组的membership_id为11。 由于civicrm_membershipperiod的每个元组与列membership_id上的另一个表的每个元组匹配,因此它找不到不匹配。因此,它产生3 * 3 = 9次匹配。
答案 2 :(得分:0)
根据您的数据,这是预期的行为。您使用JOIN
membership_id
了两张桌子。但是,civicrm_membership_payment
中membership_id = 11
的每一行与另一个表中的三个记录匹配。这就是你的结果中有3 x 3 = 9行的原因。
这看起来像是设计缺陷,您的表civicrm_membership_payment
应该有一个参考,允许它决定此付款所涉及的时间段。
dbfiddle here 了解您当前的情况。
备用:更改表格的定义以说明:
CREATE TABLE civicrm_membershipperiod
(
/* no need for a synthetic id, surrogate primary key */
membership_id INTEGER,
start_date date,
end_date date,
PRIMARY KEY (membership_id, start_date), /* "Natural" PK */
CHECK (end_date >= start_date)
) ;
INSERT INTO civicrm_membershipperiod
(membership_id, start_date, end_date)
VALUES
(11, '2015-01-01', '2015-12-31'),
(11, '2017-07-09', '2018-07-08'),
(11, '2018-07-09', '2019-07-08') ;
CREATE TABLE civicrm_membership_payment
(
contribution_id INTEGER PRIMARY KEY, /* Surrogate key, not really necessary */
membership_id INTEGER NOT NULL,
start_date date NOT NULL,
CONSTRAINT fk_civicrm_membershipperiod_civicrm_membershipperiod
FOREIGN KEY (membership_id, start_date)
REFERENCES civicrm_membershipperiod(membership_id, start_date)
) ;
INSERT INTO civicrm_membership_payment
(membership_id, contribution_id, start_date)
VALUES
(11, 39, '2015-01-01'),
(11, 40, '2017-07-09'),
(11, 41, '2018-07-09') ;
SELECT
pr.start_date,pr.end_date, p.contribution_id
FROM
civicrm_membershipperiod pr
INNER JOIN civicrm_membership_payment p
ON p.membership_id = pr.membership_id AND p.start_date = pr.start_date
WHERE
p.membership_id=11
start_date | end_date | contribution_id :--------- | :--------- | --------------: 2015-01-01 | 2015-12-31 | 39 2017-07-09 | 2018-07-08 | 40 2018-07-09 | 2019-07-08 | 41
dbfiddle here
注意:您不需要每个表都有AUTO_INCREMENT
个ID。它们在某些情况下可能很方便,但您也可以使用自然主键(列或列的组合,可以让您唯一地标识表中的行,并且具有一些含义< / em>的)。我已经使用它们而不是合成PK,我认为它们可以更好地代表手头的问题。
答案 3 :(得分:0)
正如我在评论中提到的,默认情况下,SQL不考虑数据库中行的顺序,因此它不能将一个表的第一行与另一个表的第一行匹配,依此类推。
几十年来,人们已经接受了这一点,但最近sql扩展了解决此问题的新语句。不幸的是,这还没有标准化,因此导致了SQL方言的进一步分歧。对于T-SQL,请参阅row_number()和rank()
上的此文档SELECT pr.start_date,pr.end_date, p.contribution_id
FROM (select *, ROW_NUMBER()
OVER(PARTITION BY membership_id
ORDER BY start_date ASC) as row_nr
from civicrm_membershipperiod ) pr
INNER JOIN (select *, ROW_NUMBER()
OVER(PARTITION BY membership_id
ORDER BY contribution_id ASC) as row_nr
from civicrm_membership_payment ) p
ON pr.membership_id=p.membership_id and pr.row_nr = p.row_nr
where p.membership_id=11