将位字段扩展到多行(有点连接)
Expand bit fields to multiple rows (kinda join)
假设我有这样一个 table:
CREATE TABLE [dbo].[Scheduler](
[DayOfWeek] [tinyint] NOT NULL,
[Time] [time](0) NOT NULL,
[Action] [varchar](255) NOT NULL
)
还有一些数据,例如:
INSERT INTO Scheduler VALUES (1, '11:00:00', 'Sunday')
INSERT INTO Scheduler VALUES (2, '12:00:00', 'Monday')
INSERT INTO Scheduler VALUES (4, '13:00:00', 'Tuesday')
INSERT INTO Scheduler VALUES (8, '14:00:00', 'Wednesday')
INSERT INTO Scheduler VALUES (16, '15:00:00', 'Thursday')
INSERT INTO Scheduler VALUES (32, '16:00:00', 'Friday')
INSERT INTO Scheduler VALUES (64, '17:00:00', 'Saturday')
INSERT INTO Scheduler VALUES (62, '06:00:00', 'Every business day')
INSERT INTO Scheduler VALUES (127, '08:00:00', 'Every day')
如果 DayOfWeek 有多个标志,我如何在 SELECT 语句中生成多行?
例如这一行:
INSERT INTO Scheduler VALUES (62, '06:00:00', 'Every business day')
它将在 SELECT 语句中以 5 行表示(每个 day/flag 集合一行)
DayOfWeek Time Message
--------- ---------------- ---------------------------
2 06:00:00 Every business day
4 06:00:00 Every business day
8 06:00:00 Every business day
16 06:00:00 Every business day
32 06:00:00 Every business day
运行 包含所有数据的相同查询会得到 19 行。
- 7 行 - 每一天一行(1、2、4、8、16、32、64)
- 5 行 - 工作日 (62)
- 7 行 - 每天 (127)
我不确定我该怎么做。
我想我可以使用游标来执行此操作,但它是这里的最佳选择吗?
谢谢。
您需要 SQL 服务器的 Bitwise Operators。此示例说明如何确定当前值中包含哪些标志。
DECLARE @Mon INT = 1;
DECLARE @Tue INT = 2;
DECLARE @Wed INT = 4;
DECLARE @MonAndTue INT = 3; -- Mon (1) and Tue (2) = 3.
SELECT
@MonAndTue & @Mon, -- Contains Monday, returns Monday.
@MonAndTue & @Tue, -- Contains Tuesday, returns Tuesday.
@MonAndTue & @Wed -- Does not contain Wednesday, returns 0.
我建议尽可能避免在 SQL 服务器中使用基于位掩码的解决方案。这些在其他语言中工作得很好(我想到了 C)。但是 SQL 在每列包含单个值并描述单个项目时效果最佳。当然你可以结合这些方法。这种 table 设计允许您保留基数 2 键(非常适合前端)并包含简单的位字段,使后端过滤成为一项简单的任务。
CREATE TABLE [Day]
(
DayId INT PRIMARY KEY,
[DayName] VARCHAR(9),
IsMonday BIT,
IsTuesday BIT,
...
IsSunday BIT
)
;
编辑
对不起!我实际上没有回答你的问题。要在连接中使用按位运算,您需要使用以下几行语法:
WITH Scheduler AS
(
/* Sample data.
*/
SELECT
*
FROM
(
VALUES
(1, 'Sunday'),
(2, 'Monday'),
(4, 'Tuesday'),
(8, 'Wednesday'),
(16, 'Thursday'),
(32, 'Friday'),
(64, 'Saturday'),
(62, 'Every business day'),
(127, 'Every day')
) AS r(DayId, [DayName])
)
/* This join returns every day from s2 that
* is contained within the s1 record Every business day.
*/
SELECT
*
FROM
Scheduler AS s1
INNER JOIN Scheduler AS s2 ON (s1.DayId & s2.DayId) = s2.DayId
WHERE
s1.DayId = 62
;
此处 S1 被过滤到 return 每个工作日 。 S2 在找到匹配项的地方加入 S1。 return 周一、周二、周三等,没有 return 周六和周日。
假设我有这样一个 table:
CREATE TABLE [dbo].[Scheduler](
[DayOfWeek] [tinyint] NOT NULL,
[Time] [time](0) NOT NULL,
[Action] [varchar](255) NOT NULL
)
还有一些数据,例如:
INSERT INTO Scheduler VALUES (1, '11:00:00', 'Sunday')
INSERT INTO Scheduler VALUES (2, '12:00:00', 'Monday')
INSERT INTO Scheduler VALUES (4, '13:00:00', 'Tuesday')
INSERT INTO Scheduler VALUES (8, '14:00:00', 'Wednesday')
INSERT INTO Scheduler VALUES (16, '15:00:00', 'Thursday')
INSERT INTO Scheduler VALUES (32, '16:00:00', 'Friday')
INSERT INTO Scheduler VALUES (64, '17:00:00', 'Saturday')
INSERT INTO Scheduler VALUES (62, '06:00:00', 'Every business day')
INSERT INTO Scheduler VALUES (127, '08:00:00', 'Every day')
如果 DayOfWeek 有多个标志,我如何在 SELECT 语句中生成多行?
例如这一行:
INSERT INTO Scheduler VALUES (62, '06:00:00', 'Every business day')
它将在 SELECT 语句中以 5 行表示(每个 day/flag 集合一行)
DayOfWeek Time Message
--------- ---------------- ---------------------------
2 06:00:00 Every business day
4 06:00:00 Every business day
8 06:00:00 Every business day
16 06:00:00 Every business day
32 06:00:00 Every business day
运行 包含所有数据的相同查询会得到 19 行。
- 7 行 - 每一天一行(1、2、4、8、16、32、64)
- 5 行 - 工作日 (62)
- 7 行 - 每天 (127)
我不确定我该怎么做。 我想我可以使用游标来执行此操作,但它是这里的最佳选择吗?
谢谢。
您需要 SQL 服务器的 Bitwise Operators。此示例说明如何确定当前值中包含哪些标志。
DECLARE @Mon INT = 1;
DECLARE @Tue INT = 2;
DECLARE @Wed INT = 4;
DECLARE @MonAndTue INT = 3; -- Mon (1) and Tue (2) = 3.
SELECT
@MonAndTue & @Mon, -- Contains Monday, returns Monday.
@MonAndTue & @Tue, -- Contains Tuesday, returns Tuesday.
@MonAndTue & @Wed -- Does not contain Wednesday, returns 0.
我建议尽可能避免在 SQL 服务器中使用基于位掩码的解决方案。这些在其他语言中工作得很好(我想到了 C)。但是 SQL 在每列包含单个值并描述单个项目时效果最佳。当然你可以结合这些方法。这种 table 设计允许您保留基数 2 键(非常适合前端)并包含简单的位字段,使后端过滤成为一项简单的任务。
CREATE TABLE [Day]
(
DayId INT PRIMARY KEY,
[DayName] VARCHAR(9),
IsMonday BIT,
IsTuesday BIT,
...
IsSunday BIT
)
;
编辑
对不起!我实际上没有回答你的问题。要在连接中使用按位运算,您需要使用以下几行语法:
WITH Scheduler AS
(
/* Sample data.
*/
SELECT
*
FROM
(
VALUES
(1, 'Sunday'),
(2, 'Monday'),
(4, 'Tuesday'),
(8, 'Wednesday'),
(16, 'Thursday'),
(32, 'Friday'),
(64, 'Saturday'),
(62, 'Every business day'),
(127, 'Every day')
) AS r(DayId, [DayName])
)
/* This join returns every day from s2 that
* is contained within the s1 record Every business day.
*/
SELECT
*
FROM
Scheduler AS s1
INNER JOIN Scheduler AS s2 ON (s1.DayId & s2.DayId) = s2.DayId
WHERE
s1.DayId = 62
;
此处 S1 被过滤到 return 每个工作日 。 S2 在找到匹配项的地方加入 S1。 return 周一、周二、周三等,没有 return 周六和周日。