合并sql行组

时间:2017-01-02 06:22:29

标签: sql sql-server

我的应用程序将单行数据拆分为不同的行块,这些行总是按照startdate的排序顺序。

其中rowpart = 0是开始,rowpart = 2总是结束         rowpart = 1是中间部分,可以重复n次。

我需要以诸如rowpart = 0的startdate和rowpart = 2的enddate(如果存在或者为rowpart返回enddate)之类的形式返回行

  • Rowpart = 0是新行块的开始
  • Rowpart = 2始终是块的结尾

Chunks可以分布在不同的日期。

+-----+-------------------------+-------------------------+----------+
| Id  |        startdate        |         enddate         | rowpart |
+-----+-------------------------+-------------------------+----------+
| 100 | 2016-11-30 00:00:00.000 | 2016-11-30 01:00:00.000 |        0 |
| 100 | 2016-11-30 02:00:00.000 | 2016-11-30 03:00:00.000 |        1 |
| 100 | 2016-11-30 10:00:00.000 | 2016-12-01 00:00:00.000 |        0 |
| 100 | 2016-12-01 02:00:00.000 | 2016-12-01 02:30:00.000 |        1 |
| 100 | 2016-12-01 10:00:00.000 | 2016-12-01 10:30:00.000 |        1 |
| 100 | 2016-12-01 16:00:00.000 | 2016-12-01 16:30:00.000 |        2 |
| 101 | 2016-12-11 10:00:00.000 | 2016-12-11 10:30:00.000 |        0 |
+-----+-------------------------+-------------------------+----------+

所以上面的表应该返回:

+-----+-------------------------+-------------------------+
| Id  |        startdate        |         enddate         |
+-----+-------------------------+-------------------------+
| 100 | 2016-11-30 00:00:00.000 | 2016-11-30 03:00:00.000 |
| 100 | 2016-12-30 10:00:00.000 | 2016-12-01 16:30:00.000 |
| 101 | 2016-12-11 10:00:00.000 | 2016-12-11 10:30:00.000 |
+-----+-------------------------+-------------------------+

任何帮助将不胜感激

5 个答案:

答案 0 :(得分:0)

检查这个。使用CTE和联接:

SDWebImageDownloader *manager = [SDWebImageManager sharedManager].imageDownloader;
[manager setValue:[DefaultsValues getStringValueFromUserDefaults_ForKey:kTokenKey] forHTTPHeaderField:@"authToken"];
[manager setValue:[DefaultsValues getStringValueFromUserDefaults_ForKey:kUserEmail] forHTTPHeaderField:@"email"];
[manager downloadImageWithURL:[NSURL URLWithString:@"URL STRING"] options:SDWebImageDownloaderUseNSURLCache progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {

    NSLog(@"%tu",receivedSize);

} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
    if (error == nil) {
        cell.profileImage.image = image;
    }
}];
  

OutPut:

enter image description here

答案 1 :(得分:0)

看起来只需要一个简单的Group by

试试这个

select Id,min(startdate),max(enddate)
From yourtable
Group by Id,cast(startdate as date)

答案 2 :(得分:0)

    Select 
Id, 
startdate,
 enddate 
from (
    select Id, 
startdate,
 enddate,ROW_NUMBER()OVER(PARTITION BY CONVERT(DATE,startdate) ORDER BY startdate DESC  )RN from @Table1
    GROUP BY Id, startdate, enddate)T
WHERE T.RN = 1

答案 3 :(得分:0)

这应该有效:

;WITH temp
AS
(
SELECT  Id, startdate,enddate,rowpart,
        --Find out First Record
        CASE WHEN rowpart=0
            THEN 1
            ELSE 0
        END AS is_first,
        --Find out Last Record, Check if next rowpart is 0 or NULL:
        CASE WHEN COALESCE(LEAD(rowpart) OVER (ORDER BY Id, startdate),0) = 0 --Check if next rowpart is 0 or NULL
            THEN 1
            ELSE 0
        END AS is_last
FROM    @tab
)

SELECT  DISTINCT
        Id,
        CASE WHEN is_first = 1
            THEN startdate
            ELSE LAG(startdate) OVER (ORDER BY Id, startdate) 
        END AS startdate,
        CASE WHEN is_last = 1
            THEN enddate
            ELSE LEAD(enddate) OVER (ORDER BY Id, startdate) 
        END AS enddate
FROM    temp 
WHERE   is_first = 1 OR is_last = 1
ORDER BY Id, startdate

我在这里尝试做什么:在CTE内部,我标记每个序列的第一个和最后一个记录。如果rowpart = 0 - >这是第一张唱片。如果下一条记录为空或下一条记录的行部分为0,则我们有最后一条记录。

因此,在查询CTE时,我们可以消除“两者之间的记录”。剩下的是每个序列1或2个记录(第一个和最后一个,在某些情况下,这是相同的记录)。

然后我们用序列的第一个记录的startdate替换startdate,用序列的最后一个记录的enddate替换enddate

使用DISTINCT消除重复值,即可获得所需的输出。

这是一个很脏的SQL,但至少它可以工作; - )

如果您不知道SQL Server LEADLAG函数来访问上一行或后续行值,请查看以下内容:http://blog.sqlauthority.com/2013/09/22/sql-server-how-to-access-the-previous-row-and-next-row-value-in-select-statement/

答案 4 :(得分:0)

WITH
    your_table_lead AS
(
    SELECT
        your_table.*,
         LAG(rowpart, 1, 2) OVER (PARTITION BY id
                                      ORDER BY startdate)    AS last_rowpart,
        LEAD(rowpart, 1, 0) OVER (PARTITION BY id
                                      ORDER BY startdate)    AS next_rowpart
    FROM
        your_table
),
    filtered_sorted AS
(
    SELECT
        *,
        ROW_NUMBER() OVER (PARTITION BY id
                               ORDER BY startdate)    AS id_seq_num
    FROM
        your_table_lead
    WHERE
                rowpart IN (0, 2)
        OR next_rowpart = 0
        OR last_rowpart = 2
)
SELECT
    id,
    MIN(startdate),
    MAX(enddate)
FROM
    filtered_sorted
GROUP BY
    id,
    id_seq_num - CASE rowpart WHEN 2 THEN 1 ELSE rowpart END

我在手机上,因为打字错误等道歉。

第一步只是尝试过滤掉除“每个组”的第一个和最后一个条目之外的所有内容。如果rowpart为0或2,则包含该行,或者如果Next Row的rowpart为0,则也包含该行(如果没有下一行,则使用0)。

然后'技巧'是找到一种方法来组合'对'。

如果我们的序列为0,2,0,1,0,2,2,0,那么我们想要的就是将它们分组为a,a,b,b,c,c,d,e

这可以通过将所有2变成1来完成,从ROW_NUMBER()中扣除该值。

0,2,0,1,0,2,2,0 => 0,1,0,1,0,1,1,0

1,2,3,4,5,6,7,8 - 0,1,0,1,0,1,1,0 => 1,1,3,3,5,5,6,8

所以,现在我们有5个不同的'组',我们可以在其上应用MIN()和MAX()。