在自定义列中显示日期范围 - 差距和孤岛
Show Date Range in Custom Column - Gaps and Islands
我有 table 看起来像这样:
+------------+------+
| Date | Name |
+------------+------+
| 2017-01-07 | A |
| 2017-01-08 | A |
| 2017-01-09 | A |
| 2017-01-12 | A |
| 2017-01-07 | B |
| 2017-01-08 | B |
| 2017-01-09 | B |
+------------+------+
我希望能够把它变成下面这样:
+-------------------------+------+
| Date Range | Name |
+-------------------------+------+
| 2017-01-07 - 2017-01-09 | A |
| 2017-01-07 - 2017-01-09 | B |
| 2017-01-12 | A |
+-------------------------+------+
该代码将仅查找连续日期的最小值和最大值,使用 Name 列对结果进行分组,然后将最小值和最大值列为 'to and from'一列中的字符串。
我在尝试仅列出连续日期时遇到问题。请注意,上面的第三个条目有自己的条目,因为它与较早条目中 'A' 的日期范围不连续。
编辑:请注意:这是特定于 SQL Server 2008,它不允许使用 LAG 功能。
编辑 2:
McNets 提供的原始答案在 SQL Server 2012 上运行良好。我将其包含在此处,因为如果您拥有 SQL Server 2012 及更高版本,效果会更好。
;WITH CalcDiffDays AS
(
SELECT Date, Name,
CONCAT (Name, CAST(DATEDIFF(DAY, LAG(Date, 1, Date - 1) OVER (PARTITION BY Name ORDER BY Name, Date), Date) AS VARCHAR(10))) AS NumDays
FROM @tmpTable
)
SELECT CONCAT(CONVERT(VARCHAR(20), MIN(Date), 102), ' - ', CONVERT(VARCHAR(20), MAX(Date), 102)) AS [Data Range], Name
FROM CalcDiffDays
GROUP BY NumDays, Name;
首先,我在整个 table 中添加了一个行号。
WITH RowN AS
(
SELECT Date, Name, ROW_NUMBER() OVER (ORDER BY Name, Date) RN
FROM #T
)
然后我加入了这个 table 本身只是为了计算日期之间的天数。
,CalcDiffDays AS
(
SELECT RowN.Date, RowN.Name,
ISLAND = RowN.Name +
CASE
WHEN RowN.RN > 1 AND RowN.Name = R2.Name THEN CAST(DATEDIFF(day, R2.Date, RowN.Date) AS VARCHAR(20))
ELSE '1'
END
FROM RowN
LEFT JOIN RowN R2 ON R2.RN = RowN.RN-1
)
差距。同名的连续日期之间相隔多少天。
岛屿。通过将名称添加到计算的天数。
+---------------------+------+---------+
| Date | Name | NumDays |
+---------------------+------+---------+
| 07.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 08.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 09.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 12.01.2017 00:00:00 | A | A3 |
+---------------------+------+---------+
| 07.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
| 08.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
| 09.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
第二部分:获取每个岛屿的MIN和MAX Date。
WITH RowN AS
(
SELECT Date, Name, ROW_NUMBER() OVER (ORDER BY Name, Date) RN
FROM #T
)
,CalcDiffDays AS
(
SELECT RowN.Date, RowN.Name,
ISLAND = RowN.Name +
CASE
WHEN RowN.RN > 1 AND RowN.Name = R2.Name THEN CAST(DATEDIFF(day, R2.Date, RowN.Date) AS VARCHAR(20))
ELSE '1'
END
FROM RowN
LEFT JOIN RowN R2 ON R2.RN = RowN.RN-1
)
SELECT CONVERT(VARCHAR(20), MIN(Date), 102) + ' - ' + CONVERT(VARCHAR(20), MAX(Date), 102) AS [Data Range], Name
FROM CalcDiffDays
GROUP BY ISLAND, Name
ORDER BY MIN(Date);
+-------------------------+------+
| Data Range | Name |
+-------------------------+------+
| 2017.01.07 - 2017.01.09 | A |
+-------------------------+------+
| 2017.01.07 - 2017.01.09 | B |
+-------------------------+------+
| 2017.01.12 - 2017.01.12 | A |
+-------------------------+------+
可以在这里查看:http://rextester.com/MHLEEJ50479
我有 table 看起来像这样:
+------------+------+
| Date | Name |
+------------+------+
| 2017-01-07 | A |
| 2017-01-08 | A |
| 2017-01-09 | A |
| 2017-01-12 | A |
| 2017-01-07 | B |
| 2017-01-08 | B |
| 2017-01-09 | B |
+------------+------+
我希望能够把它变成下面这样:
+-------------------------+------+
| Date Range | Name |
+-------------------------+------+
| 2017-01-07 - 2017-01-09 | A |
| 2017-01-07 - 2017-01-09 | B |
| 2017-01-12 | A |
+-------------------------+------+
该代码将仅查找连续日期的最小值和最大值,使用 Name 列对结果进行分组,然后将最小值和最大值列为 'to and from'一列中的字符串。
我在尝试仅列出连续日期时遇到问题。请注意,上面的第三个条目有自己的条目,因为它与较早条目中 'A' 的日期范围不连续。
编辑:请注意:这是特定于 SQL Server 2008,它不允许使用 LAG 功能。
编辑 2: McNets 提供的原始答案在 SQL Server 2012 上运行良好。我将其包含在此处,因为如果您拥有 SQL Server 2012 及更高版本,效果会更好。
;WITH CalcDiffDays AS
(
SELECT Date, Name,
CONCAT (Name, CAST(DATEDIFF(DAY, LAG(Date, 1, Date - 1) OVER (PARTITION BY Name ORDER BY Name, Date), Date) AS VARCHAR(10))) AS NumDays
FROM @tmpTable
)
SELECT CONCAT(CONVERT(VARCHAR(20), MIN(Date), 102), ' - ', CONVERT(VARCHAR(20), MAX(Date), 102)) AS [Data Range], Name
FROM CalcDiffDays
GROUP BY NumDays, Name;
首先,我在整个 table 中添加了一个行号。
WITH RowN AS
(
SELECT Date, Name, ROW_NUMBER() OVER (ORDER BY Name, Date) RN
FROM #T
)
然后我加入了这个 table 本身只是为了计算日期之间的天数。
,CalcDiffDays AS
(
SELECT RowN.Date, RowN.Name,
ISLAND = RowN.Name +
CASE
WHEN RowN.RN > 1 AND RowN.Name = R2.Name THEN CAST(DATEDIFF(day, R2.Date, RowN.Date) AS VARCHAR(20))
ELSE '1'
END
FROM RowN
LEFT JOIN RowN R2 ON R2.RN = RowN.RN-1
)
差距。同名的连续日期之间相隔多少天。
岛屿。通过将名称添加到计算的天数。
+---------------------+------+---------+
| Date | Name | NumDays |
+---------------------+------+---------+
| 07.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 08.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 09.01.2017 00:00:00 | A | A1 |
+---------------------+------+---------+
| 12.01.2017 00:00:00 | A | A3 |
+---------------------+------+---------+
| 07.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
| 08.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
| 09.01.2017 00:00:00 | B | B1 |
+---------------------+------+---------+
第二部分:获取每个岛屿的MIN和MAX Date。
WITH RowN AS
(
SELECT Date, Name, ROW_NUMBER() OVER (ORDER BY Name, Date) RN
FROM #T
)
,CalcDiffDays AS
(
SELECT RowN.Date, RowN.Name,
ISLAND = RowN.Name +
CASE
WHEN RowN.RN > 1 AND RowN.Name = R2.Name THEN CAST(DATEDIFF(day, R2.Date, RowN.Date) AS VARCHAR(20))
ELSE '1'
END
FROM RowN
LEFT JOIN RowN R2 ON R2.RN = RowN.RN-1
)
SELECT CONVERT(VARCHAR(20), MIN(Date), 102) + ' - ' + CONVERT(VARCHAR(20), MAX(Date), 102) AS [Data Range], Name
FROM CalcDiffDays
GROUP BY ISLAND, Name
ORDER BY MIN(Date);
+-------------------------+------+
| Data Range | Name |
+-------------------------+------+
| 2017.01.07 - 2017.01.09 | A |
+-------------------------+------+
| 2017.01.07 - 2017.01.09 | B |
+-------------------------+------+
| 2017.01.12 - 2017.01.12 | A |
+-------------------------+------+
可以在这里查看:http://rextester.com/MHLEEJ50479