我有一个表,其中包含以秒为单位的INT时间列,具有该记录类型的另一列以及一个外部ID。
我想选择同一行,只要它的秒行大于X,并且在第一行中将X保留为类型1的X秒,在第二行中则显示剩余的秒(秒-X,直至X)的类型2。与Y相同。最多3行。因此,第1行最多x,第2行最多Y,第3行是Y + 1及以上
例如:
X为5。Y为9。 我想要这个:
| id | type | seconds |
|----|------|---------|
| 1 | 10 | 19 |
| 2 | 10 | 12 |
| 3 | 10 | 7 |
成为这个:
| id | type | seconds |
|----|------|---------|
| 1 | 1 | 5 |
| 1 | 2 | 4 |
| 1 | 3 | 10 |
| 2 | 1 | 5 |
| 2 | 2 | 4 |
| 2 | 3 | 3 |
| 3 | 1 | 5 |
| 3 | 2 | 2 |
有可能吗?
我已经看到专门针对oracle的解决方案(语法-)。 但是如何在SQL Server中做到这一点?
编辑:仅对此类型的id(在示例中为10),其他参数保持不变。
答案 0 :(得分:1)
这不是很漂亮,但是可以解决问题。要复制行,我们使用计数表。在这种情况下,我使用了只有3行的硬编码代码。然后基于此进行计算。可能有一种更简单的编码方式,但是我今天还没尽力。
--Creating sample data
CREATE TABLE SampleData(
id int,
[type] int,
seconds int
);
INSERT INTO SampleData
VALUES
( 1, 10, 19),
( 2, 10, 12),
( 3, 10, 7),
( 4, 10, 5),
( 5, 10, 3);
GO
--Actual solution
DECLARE @X int = 5;
WITH CTE AS(
SELECT id,
CASE WHEN [type] = 10 THEN n ELSE [type] END AS [type],
CASE WHEN [type] <> 10 THEN seconds
WHEN n = 1 AND seconds > @X THEN @X
WHEN n = 1 AND seconds <= @X THEN seconds
WHEN n = 2 AND seconds - @X >= @X THEN @X-1
WHEN n = 2 AND seconds - @X > 0 THEN seconds - @X
WHEN n = 3 AND seconds > @X*2-1 THEN seconds - (@X*2-1)
END AS seconds
FROM SampleData
CROSS JOIN( VALUES(1),(2),(3))AS x(n)
WHERE [type] = 10 OR n = 1
)
SELECT *
FROM CTE
WHERE seconds IS NOT NULL;
答案 1 :(得分:0)
对于这种类型的问题,我喜欢使用recursive CTE。从@Luis Cazares借用了额外的测试用例。还添加了您在注释中提到的类型15的测试用例。在下面的解决方案中,您可以交换X和Y的值,它将相应地进行计算。
CREATE TABLE #TestData
(
id INT
, type INT
, seconds int
);
INSERT INTO #TestData VALUES
(1, 10, 19)
, (2, 10, 12)
, (3, 10, 7)
, (4, 10, 5)
, (5, 10, 3)
, (6, 15, 54)
, (7, 15, 8);
DECLARE
@X INT = 5
, @Y INT = 9;
SET @Y = @Y - @X;
WITH CTE AS
(
SELECT id, CASE WHEN type = 10 THEN 0 ELSE type END AS type, seconds, seconds AS ov
FROM #TestData
UNION ALL
SELECT
id
, type + 1
, CASE
WHEN type = 0 THEN seconds - @X
WHEN type = 1 THEN seconds - @Y
WHEN type = 2 THEN seconds
END
, ov
FROM CTE
WHERE seconds > 0
)
SELECT
id
, type
, CASE
WHEN type = 1 AND seconds > 0 THEN @X
WHEN type = 2 AND seconds > 0 THEN @Y
WHEN type = 2 AND seconds < 0 THEN ov - @X
WHEN type = 3 AND seconds > 0 THEN seconds
ELSE ov
END
FROM CTE
WHERE type <> 0 AND CTE.seconds IS NOT NULL
ORDER BY id, type
DROP TABLE #TestData;