2016-07-05 60 views
2

我正在查找SQL查询(或者甚至更好的LINQ查询)以删除已经取消了他们的假的人,即删除具有相同NAME和相同START和END以及DAYS_TAKEN的所有记录值仅在符号上有所不同。删除所有具有相反符号的记录

如何从这个

NAME |DAYS_TAKEN |START  |END  |UNIQUE_LEAVE_ID  
--------|-----------|-----------|-----------|----------- 
Alice | 2  | 1 June | 3 June | 1 --remove because cancelled 
Alice | -2  | 1 June | 3 June | 2 --cancelled 
Alice | 3  | 5 June | 8 June | 3 --keep 
Bob  | 10  | 4 June | 14 June | 4 --keep 
Charles | 12  | 2 June | 14 June | 5 --remove because cancelled 
Charles | -12  | 2 June | 14 June | 6 --cancelled 
David | 5   | 3 June | 8 June | 7 --keep 

为此得到什么?

NAME |DAYS_TAKEN |START  |END  |UNIQUE_LEAVE_ID  
--------|-----------|-----------|-----------|----------- 
Alice | 3  | 5 June | 8 June | 3 --keep 
Bob  | 10  | 4 June | 14 June | 4 --keep 
David | 5   | 3 June | 8 June | 7 --keep 

我已经试过

查询1找出所有被取消的记录(不知道这是正确的)

SELECT L1.UNIQUE_LEAVE_ID 
FROM LEAVE L1 
INNER JOIN LEAVE L2 ON L2.DAYS_TAKEN > 0 AND ABS(L1.DAYS_TAKEN) = L2.DAYS_TAKEN AND L1.NAME= L2.NAME AND L1.START = L2.START AND L1.END = L2.END 
WHERE L1.DAYS_TAKEN < 0 

然后我用查询1两次在内部选择像这样

SELECT L.* FROM LEAVE L WHERE 
L.UNIQUE_LEAVE_ID NOT IN (Query1) 
AND L.UNIQUE_LEAVE_ID NOT IN (Query1) 

有没有办法只使用一次内部查询?

(它是一个Oracle数据库,正在从.NET/C#调用)

回答

2

您可以使用查询类似如下:

SELECT NAME, START, END 
FROM LEAVE 
GROUP BY NAME, START, END 
HAVING SUM(DAYS_TAKEN) = 0 

,以获得已取消NAME, START, END组(假设取消记录的DAYS_TAKEN取消初始记录的日期)。

输出:

NAME |START  |END   
--------|-----------|---------- 
Alice | 1 June | 3 June 
Charles | 2 June | 14 June 

使用上述查询作为派生表,你可以得到不被涉及到 '取消' 组记录:

SELECT L1.NAME, L1.DAYS_TAKEN, L1.START, L1.END, L1.UNIQUE_LEAVE_ID 
FROM LEAVE L1 
LEFT JOIN (
    SELECT NAME, START, END 
    FROM LEAVE 
    GROUP BY NAME, START, END 
    HAVING SUM(DAYS_TAKEN) = 0 
) L2 ON L1.NAME = L2.NAME AND L1.START = L2.START AND L1.END = L2.END 
WHERE L2.NAME IS NULL 

输出:

NAME |DAYS_TAKEN |START  |END  |UNIQUE_LEAVE_ID  
--------|-----------|-----------|-----------|----------- 
Alice | 3   | 5 June | 8 June | 3 
Bob  | 10  | 4 June | 14 June | 4 
David | 5   | 3 June | 8 June | 7 
1

您可以使用not exists

select l.* 
from leave l 
where not exists (select 1 
        from leave l2 
        where l2.name = l.name and l2.start = l.start and 
         l2.end = l.name and l2.days_taken = - l.days_taken 
       ); 

这种查询可以在leave(name, start, end, days_taken)采取指数的优势。

1

这里是SUM() OVER变化:

SELECT x.* 
    FROM (SELECT l.*, SUM (days_taken) OVER (PARTITION BY name, "START", "END", ABS (days_taken) ORDER BY NULL) s 
      FROM leave l) x 
WHERE s <> 0 

如果你有甲骨文12,这个给你取消:

SELECT l.* 
    FROM leave l, 
     LATERAL (SELECT days_taken 
        FROM leave l2 
       WHERE l2.name = l.name 
        AND l2."START" = l."START" 
        AND l2."END" = l."END" 
        AND l2.days_taken = -l.days_taken) x 

,这应该留什么:

SELECT l.* 
    FROM leave l 
     OUTER APPLY (SELECT days_taken 
         FROM leave l2 
        WHERE l2.name = l.name 
         AND l2."START" = l."START" 
         AND l2."END" = l."END" 
         AND l2.days_taken = -l.days_taken) x 
WHERE x.days_taken IS NULL 

还有一些关于列名的内容。不建议在Oracle SQL中使用保留字,但如果你必须这样做,请使用'''就像这里。

0

我用Giorgos答案想出了这个Linq解决方案。该解决方案还考虑多次取消/休假的人员。见下面的爱丽丝和埃德加。

的样本数据

int id = 0; 
    List<Leave> allLeave = new List<Leave>() 
    { 
    new Leave() { UniqueLeaveID=id++, Name="Alice", Start=new DateTime(2016,6,1), End=new DateTime(2016,6,3), Taken=-2 }, 
    new Leave() { UniqueLeaveID=id++,Name="Alice", Start=new DateTime(2016,6,1), End=new DateTime(2016,6,3), Taken=2 }, 
    new Leave() { UniqueLeaveID=id++, Name="Alice", Start=new DateTime(2016,6,1), End=new DateTime(2016,6,3), Taken=2 }, 
    new Leave() { UniqueLeaveID=id++,Name="Alice", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,5), Taken=3 }, 

    new Leave() { UniqueLeaveID=id++,Name="Bob", Start=new DateTime(2016,6,4), End=new DateTime(2016,6,14), Taken=10 }, 

    new Leave() { UniqueLeaveID=id++,Name="Charles", Start=new DateTime(2016,6,2), End=new DateTime(2016,6,14), Taken=12 }, 
    new Leave() { UniqueLeaveID=id++,Name="Charles", Start=new DateTime(2016,6,2), End=new DateTime(2016,6,14), Taken=-12 }, 

    new Leave() { UniqueLeaveID=id++,Name="David", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,8), Taken=5 }, 

      new Leave() { UniqueLeaveID=id++,Name="Edgar", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,8), Taken=5 }, 
    new Leave() { UniqueLeaveID=id++,Name="Edgar", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,8), Taken=5 }, 
    new Leave() { UniqueLeaveID=id++,Name="Edgar", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,8), Taken=5 }, 
    new Leave() { UniqueLeaveID=id++,Name="Edgar", Start=new DateTime(2016,6,3), End=new DateTime(2016,6,8), Taken=5 } 

    }; 

LINQ查询(当心Oracle版本11 VS 12)

var filteredLeave = allLeave 
.GroupBy(a => new { a.Name, a.Start, a.End }) 
.Select(a => new { Group = a.OrderByDescending(b=>b.Taken), Count = a.Count() }) 
.Where(a => a.Count % 2 != 0) 
.Select(a => a.Group.First()); 

“OrderByDescending” 确保采取只返回正天。

的Oracle SQL

SELECT 
* 
FROM 
(
    SELECT 
    L1.NAME, L1.START, L1.END, MAX(TAKEN) AS TAKEN, COUNT(*) AS CNT 
    FROM LEAVE L1 
    GROUP BY L1.NAME, L1.START, L1.END 
) L2 
WHERE MOD(L2.CNT,2)<>0 -- replace MOD with % for Microsoft SQL 

条件 “WHERE MOD(L2.CNT,2)<> 0”(或Linq中的 “a.Count%2!= 0”)只返回谁使用一次的人或者奇数次(例如申请 - 取消 - 申请)。但申请 - 取消 - 申请 - 取消的人被过滤掉。

相关问题