如何从期间列中选择值作为行?

时间:2019-06-08 18:21:05

标签: sql sql-server tsql

我有一张产品订单属性表。

OrderId     |  SerialFrom        |  Serial To
1           |  6605181145833976  |  6605181145833980

如何以这种方式显示它:

SerialId
6605181145833976
6605181145833977
6605181145833978
6605181145833979

谢谢。

2 个答案:

答案 0 :(得分:1)

您需要递归 CTE 作为

CREATE TABLE Data(
  OrderId INT,
  SerialFrom BIGINT,
  SerialTo BIGINT
);

INSERT INTO Data VALUES
(1, 6605181145833976, 6605181145833980);

WITH CTE AS
(
  SELECT SerialFrom
  FROM Data
  UNION ALL
  SELECT SerialFrom + 1
  FROM CTE
  WHERE CTE.SerialFrom < 6605181145833979
)
SELECT SerialFrom SerialId
FROM CTE;

返回:

+------------------+
|     SerialId     |
+------------------+
| 6605181145833976 |
| 6605181145833977 |
| 6605181145833978 |
| 6605181145833979 |
+------------------+

由于已知行数,并且只有4个值,因此您也可以将 Table Value Constructor (在这种情况下,这是最佳选择)用作

SELECT SerialFrom + Number SerialId
FROM Data D CROSS JOIN 
     (VALUES (0), (1), (2), (3)) T(Number);

您还可以对master..spt_values系统表执行以下操作

SELECT SerialFrom + Number SerialId
FROM Data D CROSS JOIN 
     master..spt_values T
WHERE T.[Type] = 'P'
      AND
      [Number] <= 3;

有鉴于此,我建议不要使用master..spt_values系统表,因为它没有记录,并且Microsoft可以在不警告的情况下更改未记录的系统表,因此应避免使用它们。仍然是您的选择:)。

最后,这是一个 db<>fiddle ,可以用来查看其工作原理。

答案 1 :(得分:0)

数字计数表会有所帮助。它可以是预定义的表,也可以根据以下查询动态创建。

with L0(N) as (
    select top(10) null from sys.all_objects
),L1(N) as (--  10**2
    select null 
    from L0 a1
    cross join L0 a2
),L2(N) as (--  10**2**2
    select null 
    from L1 a1
    cross join L1 a2
), tally as(
        select n = row_number() over(order by N) - 1
        from L2
)
select OrderId, SerialFrom + n 
from Mytable mt
join tally t on t.n <= SerialTo - SerialFrom