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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我需要帮助写一个复杂的SQL语句相关的知识,希望对你有一定的参考价值。

**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个表:施主表和承诺表。我想运行一个返回每对夫妇只有一个记录谁已经在往年,今年给定的,但没有(特别是最大或最近承诺日期)查询。因为最优秀的人募捐到的过去的捐献这是我们的非营利性非常重要。然而,在我们的数据库中,有时妻子给和明年丈夫给予所以它是既之下。有些没有结婚。

所以在上面的表格中,只有约翰·亚当在2012年承诺,杰克·约翰逊在2009年的承诺,应当返还。简·史密斯应该,但因为她的丈夫今年给了她自2012年给出不连返回。

答案

我没有测试过,但像下面应该工作:

(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 <dt.spouse_id以避免重复。此外,在该查询我做了左外连接在这两种情况下,否则你可能会错过的结果。可能有轻微的语法错误,但这样的事情应该工作。我也把日期“2014年1月1日”,使其返回您在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

为了简化你可以定义一个函数,该函数。它基本上是计算配偶及捐赠者的最大价值,其中一个或多个值是空

另一答案

没有确切知道你正在使用的数据库,使更难提出解决方案。我假设你的数据库支持公共表表达式和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

分贝<>小提琴here

以上是关于我需要帮助写一个复杂的SQL语句的主要内容,如果未能解决你的问题,请参考以下文章

程序中使用嵌套的sql语句和在数据库中写存储过程调用它,有啥区别?

写些小工具来帮助工作更有效率

sql语句字符串的嵌套问题

12.ORM模型

mybatis与hibernate区别

mybatis与hibernate区别