我需要帮助编写复杂的SQL语句

时间:2014-12-17 23:37:08

标签: sql nested max

**PLEDGE TABLE**
PledgeID  PledgeAmount  PledgeDate   DonorID   
---------|-------------|------------|---------
1        | 100         | 04/03/2014 | 1
2        | 200         | 04/03/2013 | 1
3        | 100         | 04/03/2009 | 2
4        | 2,000       | 01/01/2012 | 3
5        | 1,000       | 01/01/2012 | 4
6        | 500         | 01/01/2009 | 4

**DONOR TABLE**
DonorID   Name           SpouseID    
---------|-------------|-------------
1        | John Smith  | 3
2        | Jack Johnson| NULL
3        | Jane Smith  | 1
4        | John Adams  | NULL

我有2个表:一个捐赠者表和一个承诺表。我想运行一个查询,每个夫妇只返回一条记录(特别是最近或最近的承诺日期),这些记录在前几年但不是今年给出。这对我们的非营利组织来说非常重要,因为最好的募捐者是过去的捐赠者。然而,在我们的数据库中,有时候妻子给出了,而第二年,丈夫给予了,所以它在两者之下。有些人没有结婚。

因此,在上表中,只有John Adam在2012年的承诺和杰克约翰逊在2009年的承诺才能归还。简史密斯不应该归还,因为自2012年以来她没有给她,因为她的丈夫今年给了她。

2 个答案:

答案 0 :(得分:0)

我还没有测试过,但以下内容应该可以使用:

(select dt.donor_id, null spouse_id, max(pledge_date) maxDate
from donor_table dt inner join pledge_table pt on (pt.donor_id = dt.donor_id)
where dt.spouse_id is null group by dt.donor_id
having max(pledge_date) is not null and max(pledge_date) < '2014-01-01'
union distinct
(select dt.donor_id, dt.spouse_id
      ,case when max(pt1.pledge_date) is null then max(pt2.pledge_date) else when   
       max(pt2.pledge_date is null then max(pt1.pledge_date) else   
       greatest(max(pt1.pledge_date), max(pt2.pledge_date)) end maxDate
 from donor_table dt left outer join pledge_table pt1 on (pt1.donor_id = dt.donor_id)
 left outer join pledge_table pt2 on (pt2.donor_id = dt.spouse_id)
 where dt.donor_id < dt.spouse_id
 group by dt.donor_id, dt.spouse_id
 having case when max(pt1.pledge_date) is null then max(pt2.pledge_date) else when   
       max(pt2.pledge_date is null then max(pt1.pledge_date) else   
       greatest(max(pt1.pledge_date), max(pt2.pledge_date)) end is not null 
 and case when max(pt1.pledge_date) is null then max(pt2.pledge_date) else when   
       max(pt2.pledge_date is null then max(pt1.pledge_date) else   
       greatest(max(pt1.pledge_date), max(pt2.pledge_date)) end < '2014-01-01'
 )

没有配偶的捐赠者的第一个查询返回值。第二个为我使用dt.donor_id&lt;的夫妇返回对。 dt.spouse_id以避免重复。同样在该查询中,我在两种情况下都执行左外连接,否则您可能会错过结果。可能存在轻微的语法错误,但这样的事情应该有效。我还将日期'2014-01-01'设置为返回您在2013年或之前但未在2014年捐赠的捐赠者

我正在使用mysql中最强大的功能。

看起来很复杂,因为我正在重复

 case when max(pt1.pledge_date) is null then max(pt2.pledge_date) else when   
       max(pt2.pledge_date is null then pt1.pledge_date else   
       greatest(max(pt1.pledge_date), max(pt2.pledge_date)) end

为简化起见,您可以为此定义一个函数。它基本上计算配偶和捐赠者的最大价值,其中一个或多个值为空

答案 1 :(得分:0)

在不确切知道您使用哪个数据库的情况下,提出解决方案的难度要大得多。我假设您的数据库支持公用表表达式以及concat()year()函数。如果这不是真的,那么有简单的选择。

这是建议的解决方案:

with couples as (
    select 
           case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
               when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
               else concat(d.DonorID,d.SpouseID)
           end as combinedid
         , case when d.SpouseID IS NULL then d.name
                when d.SpouseID < d.DonorID then concat(s.name,d.name)
                else concat(d.name, s.name)
           end as names
    from Donors d
    left join Donors s on d.spouseid = s.donorid
    )
select distinct
     couples.names, p.MaxPledgeYear
from couples
left join (
    select
          case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
               when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
               else concat(d.DonorID,d.SpouseID)
          end as combinedid
        , max(year(PledgeDate)) MaxPledgeYear
    from pledges p
    left join donors d on p.donorid = d.donorid
    group by
          case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
               when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
               else concat(d.DonorID,d.SpouseID)
          end
    ) p on couples.combinedid = p.combinedid
where p.MaxPledgeYear < 2019

它产生了以下结果:

+----------------------+---------------+
|        names         | MaxPledgeYear |
+----------------------+---------------+
| Jack Johnson         |          2009 |
| John Adams           |          2012 |
| John SmithJane Smith |          2014 |
+----------------------+---------------+

从此结果中,您可以使用where子句排除“今年捐赠”的任何行。由于“今年”已经过了2014年,因此该列表中没有人承诺“今年”。

更多细节:

CREATE TABLE Pledges(
   PledgeID     INTEGER  NOT NULL PRIMARY KEY 
  ,PledgeAmount VARCHAR(13) NOT NULL
  ,PledgeDate   DATE  NOT NULL
  ,DonorID      INTEGER  NOT NULL
);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (1,'100','04/03/2014',1);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (2,'200','04/03/2013',1);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (3,'100','04/03/2009',2);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (4,'2,000','01/01/2012',3);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (5,'1,000','01/01/2012',4);
INSERT INTO Pledges(PledgeID,PledgeAmount,PledgeDate,DonorID) VALUES (6,'500','01/01/2009',4);
CREATE TABLE Donors(
   DonorID  INTEGER  NOT NULL PRIMARY KEY 
  ,Name     VARCHAR(13) NOT NULL
  ,SpouseID INTEGER 
);
INSERT INTO Donors(DonorID,Name,SpouseID) VALUES (1,'John Smith',3);
INSERT INTO Donors(DonorID,Name,SpouseID) VALUES (2,'Jack Johnson',NULL);
INSERT INTO Donors(DonorID,Name,SpouseID) VALUES (3,'Jane Smith',1);
INSERT INTO Donors(DonorID,Name,SpouseID) VALUES (4,'John Adams',NULL);
with couples as (
    select 
           case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
               when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
               else concat(d.DonorID,d.SpouseID)
           end as combinedid
         , case when d.SpouseID IS NULL then d.name
                when d.SpouseID < d.DonorID then concat(s.name,d.name)
                else concat(d.name, s.name)
           end as names
    from Donors d
    left join Donors s on d.spouseid = s.donorid
    )
select
     *
from couples
combinedid | names               
:--------- | :-------------------
13         | John SmithJane Smith
-2         | Jack Johnson        
13         | John SmithJane Smith
-4         | John Adams          
select
      case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
           when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
           else concat(d.DonorID,d.SpouseID)
      end as combinedid
    , max(year(PledgeDate)) MaxPledgeYear
from pledges p
left join donors d on p.donorid = d.donorid
group by
      case when d.SpouseID IS NULL then concat('',(d.DonorID * -1))
           when d.SpouseID < d.DonorID then concat(d.SpouseID,d.DonorID)
           else concat(d.DonorID,d.SpouseID)
      end
combinedid | MaxPledgeYear
:--------- | ------------:
13         |          2014
-2         |          2009
-4         |          2012

db <>提琴here