2017-05-03 86 views
0
Create table test123 (
    CustId int, 
    [Level] int, 
    RowNum int, 
    USAFlag bit 
) 

insert into test123(CustId,[Level],RowNum,USAFlag)values 
(101,1,1,0), 
(102,2,1,0), 
(102,2,2,1), 
(103,3,1,0), 
(103,3,2,1), 
(103,3,3,0), 
(104,4,1,1), 
(104,4,2,0), 
(104,4,3,0), 
(104,4,4,1), 
(105,2,1,1), 
(105,2,2,0), 
(106,2,1,0), 
(106,2,2,0), 
(107,3,1,0), 
(107,3,2,0), 
(107,3,3,1), 
(108,1,1,1) 

輸出SQL查詢,需要根據最小和最大派生列

CustID USARootLeaf 
101 ONlyONeLevel_NonUSA 
102 Leaf_USA 
103 Root_Leaf_NonUSA 
104 Root_Leaf_USA 
105 Root_USA 
106 Root_Leaf_NonUSA 
107 Leaf_USA 
108 OnlyOneLvel_USA 

邏輯: 如果級別爲1,則基於USAFlag值USARootLeaf值應OnlyOneLvel_USA或OnlyOneLvel_NonUSA

如果級別大於1,則USARootLeaf值應爲Root_Leaf_USA,Root_Leaf_NonUSA,Root_USA,Leaf_USA,基於USAFlag的最小(級別)和最大(級別)值爲true/false

+1

目前尚不清楚什麼時候是Leaf ......什麼時候是Root_Leaf ...... – FLICKER

+0

如果Level> 1,您可以給出更多邏輯細節嗎? – Jason

回答

0

感謝布萊恩和傑森您的快速輸入。 我自己找到了更好的解決方案。

with one as 
(
Select CustId,[Level], 
STUFF((SELECT ',' + cast(USAFlag as char(1)) FROM test123 WHERE (
CustId=Result.CustId) FOR XML PATH ('')),1,1,'') AS USAList 
From test123 AS Result 
GROUP BY CustId,[Level] 
) 
Select CustId,[level],USAList, 
case 
when Level=1 and substring(USAList,1,1)='1' then 'ONlyONeLevel_USA' 
when Level=1 and substring(USAList,1,1)='0' then 'ONlyONeLevel_NonUSA' 
when Level>1 and substring(USAList,1,1)='1' and substring(USAList,level*2- 
1,1)='1' then 'Root_Leaf_USA' 
when Level>1 and substring(USAList,1,1)='0' and substring(USAList,level*2- 
1,1)='0' then 'Root_Leaf_NonUSA' 
when Level>1 and substring(USAList,1,1)='1' then 'Root_USA' 
when Level>1 and substring(USAList,level*2-1,1)='1' then 'Leaf_USA' 
else 'InvalidLevel' 
end as USARootLeaf 
from one 
0

我從來沒有在查詢中使用過這麼多的CTE,我確信有一種更有效的方式,但是這種方法可行。

--Add Row Numbers 
WITH preselect AS (SELECT ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY 
        CustId)'RowNum',CustId 
        FROM test123), 

--Get the first and last Row 
preselect2 AS (SELECT MIN(RowNum)'MinRow',MAX(RowNum)'MaxRow',CustId 
       FROM preselect 
       GROUP BY CustId), 

--Join to table with data 
preselect3 AS (SELECT ROW_NUMBER() OVER(PARTITION BY t.CustId ORDER BY 
       t.CustId)'RowNumber',t.CustId,t.Level, 
       t.RowNum,t.USAFlag,p2.MinRow,p2.MaxRow 
       FROM test123 t 
       JOIN preselect2 p2 ON t.CustId = p2.CustId), 

--Filter out any row that isn't the first or last in the group 
preselect4 AS (SELECT * 
       FROM preselect3 
       WHERE RowNumber = MinRow 
        OR 
        RowNumber = MaxRow), 

--Get count of each CustId 
preselect5 AS (SELECT CustId,COUNT(*)'Cnt' 
       FROM test123 
       GROUP BY CustId), 

--Determine the properties for each CustId 
preselect6 AS (
SELECT p4.CustId, 
SUM(CASE WHEN Cnt > 1 THEN 1 ELSE 0 END) AS 'Multi', 
SUM(CASE WHEN RowNumber = 1 AND USAFlag = 1 THEN 1 ELSE 0 END)AS 'RootUSA', 
SUM(CASE WHEN RowNumber > 1 AND USAFlag = 1 THEN 1 ELSE 0 END)AS 'LeafUSA' 
FROM preselect4 p4 
    JOIN preselect5 p5 ON p4.CustId = p5.CustId 
GROUP BY p4.CustId) 

--Apply values based on their properties 
SELECT CustId, 
CASE WHEN Multi = 0 AND RootUSA = 0 THEN 'OnlyOneLevel_NonUSA' 
     WHEN Multi = 0 AND RootUSA = 1 THEN 'OnlyOneLevel_USA' 
     WHEN Multi > 1 AND RootUSA = 0 AND LeafUSA = 1 THEN 'Leaf_USA' 
     WHEN Multi > 1 AND RootUSA = 0 AND LeafUSA = 0 THEN 'Root_Leaf_NonUSA' 
     WHEN Multi > 1 AND RootUSA = 1 AND LeafUSA = 1 THEN 'Root_Leaf_USA' 
     WHEN Multi > 1 AND RootUSA = 1 AND LeafUSA = 0 THEN 'Root_USA' 
     ELSE 'N/A' END AS 'USARootLeaf' 
FROM preselect6    
0

這可以被重構爲更小,但這是基於上述要求的實現的猜測。 請注意,我在我的DDL中將[Level]更改爲thisLevel。

mysql> select q.custid, concat(q.type,concat('_',q.starsandstripes)) as type from (
    -> select 
    ->  z.custid, 
    ->  case when minlevel = 1 and maxlevel = 1 then 'OnlyOneLevel' 
    ->  else 
    ->   case when lastflag = 1 and firstflag = 0 then 'Leaf' 
    ->   when lastflag = 0 and firstflag = 1 then 'Root' 
    ->   when lastflag = firstflag then 'Root_Leaf' 
    ->   end 
    ->  end as type, 
    ->  starsandstripes 
    ->  from 
    -> (
    -> select 
    -> za.custid, 
    -> case when max(za.usaflag) = 1 
    ->  then 'USA' 
    ->  else 'NonUSA' 
    -> end 
    ->  as starsAndStripes 
    -> from test123 za join 
    ->  (
    ->   select 
    ->   custid, 
    ->   max(rownum) as maxrow, 
    ->   min(rownum) as minrow 
    ->   from test123 zc 
    ->   group by custid 
    -> ) zb 
    ->  on za.custid = zb.custid 
    ->  and (za.rownum = zb.maxrow 
    ->  or za.rownum = zb.minrow) 
    -> group by za.custid 
    ->) z, 
    -> (
    -> select 
    ->  a.custid, 
    ->  (select usaflag from test123 d where d.custid = a.custid and d.rownum = b.maxrow) as lastFlag, 
    ->  (select usaflag from test123 d where d.custid = a.custid and d.rownum = b.minrow) as firstFlag, 
    ->  min(thisLevel) as minLevel, 
    ->  max(thisLevel) as maxLevel 
    -> from test123 a join 
    -> (
    ->  select custid, max(rownum) as maxrow, min(rownum) as minrow 
    ->  from test123 c 
    ->  group by custid 
    -> ) b 
    -> on a.custid = b.custid 
    -> group by custid, 
    -> (select usaflag from test123 d where d.custid = a.custid and d.rownum = b.maxrow), 
    -> (select usaflag from test123 d where d.custid = a.custid and d.rownum = b.minrow) 
    ->) x 
    -> where z.custid = x.custid 
    ->) q; 

輸出:

+--------+---------------------+ 
| custid | type    | 
+--------+---------------------+ 
| 101 | OnlyOneLevel_NonUSA | 
| 102 | Leaf_USA   | 
| 103 | Root_Leaf_NonUSA | 
| 104 | Root_Leaf_USA  | 
| 105 | Root_USA   | 
| 106 | Root_Leaf_NonUSA | 
| 107 | Leaf_USA   | 
| 108 | OnlyOneLevel_USA | 
+--------+---------------------+ 
8 rows in set (0.00 sec)