应用WHERE过滤器外的SELECT列

时间:2017-08-17 20:51:59

标签: sql sql-server select sql-server-2012 where-clause

+----------+---------+--------+------+------------+-----------+
| PersonID | OrderID | PlanID | Plan | Sdate      | Edate     |
+----------+---------+--------+------+------------+-----------+
| 1        | 1       | 312    | M    | 10/14/2016 | 1/30/2017 |
| 1        | 4       | 125    | A    | 10/18/2016 | 2/3/2017  |
| 1        | 7       | 411    | B    | 10/25/2016 | 4/7/2017  |
| 2        | 1       | 111    | E    | 10/31/2016 | 4/21/2017 |
| 2        | 3       | 312    | M    | 11/4/2016  | 4/28/2017 |
| 2        | 5       | 253    | L    | 11/29/2016 | 5/3/2017  |
| 3        | 1       | 50     | Q    | 12/2/2016  | 5/8/2017  |
| 3        | 2       | 12     | W    | 12/8/2016  | 6/8/2017  |
| 3        | 4       | 312    | M    | 12/22/2016 | 6/26/2017 |
| 3        | 6       | 53     | Z    | 12/27/2016 | 7/10/2017 |
+----------+---------+--------+------+------------+-----------+

我需要以下输出:

+----------+------------+-----------+----------+----------+
| PersonID | SDateM     | EDateM    | MinPlan1 | MinPlan2 |
+----------+------------+-----------+----------+----------+
| 1        | 10/14/2016 | 1/30/2017 | M        | A        |
| 2        | 11/4/2016  | 4/28/2017 | E        | M        |
| 3        | 12/22/2016 | 6/26/2017 | Q        | W        |
+----------+------------+-----------+----------+----------+

当Plan = M时,SDateM是SDate,当Plan = M时,EDateM是Edate,MinPlan1是人的最小OrderID的计划。 MinPlan2是一个人的第二低OrderID计划。

我在WHERE子句中应用PlanID = 312,但这限制了我选择MinPlans的能力。我不知道如何编写代码来提取MinPlan1和MinPlan2。

尝试:

SELECT
    PersonID
    ,Sdate AS SDateM
    ,Edate AS EDateM
    ,MinPlan1
    ,MinPlan2
FROM 
    T1
WHERE 
    1 = 1
    AND PlanID = 312

3 个答案:

答案 0 :(得分:1)

您可以使用row_number和条件聚合来执行此操作。

SELECT PersonID
,MAX(CASE WHEN plan='M' then Sdate END) AS SDateM
,MAX(CASE WHEN plan='M' then Edate END) AS EDateM
,MAX(CASE WHEN rnum=1 then plan END) AS MinPlan1
,MAX(CASE WHEN rnum=2 then plan END) AS MinPlan2
FROM (SELECT t1.*,row_number() over(partition by personId order by orderId) as rnum
      FROM T1
     ) t
GROUP BY PersonID

答案 1 :(得分:1)

我认为条件聚合与row_number()的组合可以解决问题:

select personid, 
       min(case when plan = 'M' then sdate end) as sdateM,
       min(case when plan = 'M' then edate end) as edateM,
       max(case when seqnum = 1 then plan end) as plan_1,
       max(case when seqnum = 2 then plan end) as plan_2
from (select t1.*,
             row_number() over (partition by personid order by orderid) as seqnum
      from t1
     ) t1
group by person_id;

答案 2 :(得分:1)

CREATE TABLE t_plan
(personID INT,
 orderID INT,
 planID INT,
 plan_n VARCHAR(20),
 sdate DATE,
 edate DATE
)

INSERT INTO t_plan
VALUES(1,1,312,'M','10/14/2016','1/30/2017'), 
(1,4,125,'A','10/18/2016','2/3/2017'), 
(1,7,411,'B','10/25/2016','4/7/2017'),  
(2,1,111,'E','10/31/2016','4/21/2017'), 
(2,3,312,'M','11/4/2016','4/28/2017'), 
(2,5,253,'L','11/29/2016','5/3/2017'),  
(3,1,50 ,'Q','12/2/2016','5/8/2017'),  
(3,2,12 ,'W','12/8/2016','6/8/2017'),  
(3,4,312,'M','12/22/2016','6/26/2017'), 
(3,6,53 ,'Z','12/27/2016','7/10/2017')

SELECT personid, 
       MIN(CASE WHEN plan_n = 'M' THEN sdate END) sdateM,
       MIN(CASE WHEN plan_n = 'M' THEN edate END) edateM,
       MAX(CASE WHEN rnum = 1 THEN plan_n END) minplan1,
       MAX(CASE WHEN rnum = 2 THEN plan_n END) minplan2
  FROM (SELECT *,
               ROW_NUMBER() OVER (PARTITION BY personid ORDER BY orderid) rnum
          FROM t_plan
       ) t
 GROUP BY personid;

结果

personid    sdateM      edateM      minplan1    minplan2
1           2016-10-14  2017-01-30  M           A
2           2016-11-04  2017-04-28  E           M
3           2016-12-22  2017-06-26  Q           W