2016-02-03 7 views
0

скажем, у меня есть таблица вроде этого:Расширьте битовых полей в несколько строк (любопытное соединение)

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') 

Как я могу производить несколько строк в инструкция SELECT, если DayOfWeek имеет более одного флага?

Например, эта строка:

INSERT INTO Scheduler VALUES (62, '06:00:00', 'Every business day') 

Он будет представлен в 5 строк в ЗЕЬЕСТ (по одному для каждого набора день/флаг)

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)

Я не уверен, как я могу это сделать. Я думаю, что могу использовать курсор для этого, но это лучший вариант здесь?

Спасибо.

+0

Непонятно, почему вы, например, превращаетесь в эти 5 строк, можете ли вы расширить это? – sagi

+0

Конечно, я могу ... DayOfWeek = 62 Это представляет 2 + 4 + 8 + 16 + 32 = 62 соответственно: понедельник + вторник + среда + четверг + жара. Таким образом, чтобы одна строка представляла 5 дней недели, будет выполняться одна и та же задача. – navossoc

+0

Все ли эти ценности у вас в таблице? Или у вас могут быть и другие ценности? –

ответ

0

Вам нужен SQL Server 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 Server. Они отлично работают на других языках (C пружины). Но SQL работает лучше всего, когда каждый столбец содержит одно значение, описывающее один элемент. Конечно, вы могли бы объединить эти подходы. Этот дизайн таблицы позволяет сохранить базовые 2 клавиши (отлично подходит для интерфейса) и включает в себя простые битовые поля, которые делают фильтрацию в бэкэнде простой задачей.

CREATE TABLE [Day] 
(
    DayId  INT PRIMARY KEY,   
    [DayName] VARCHAR(9), 
    IsMonday BIT, 
    IsTuesday BIT, 
    ... 
    IsSunday BIT 
) 
; 

EDIT

Извините! Я не ответил на ваш вопрос. Для того, чтобы использовать битовые операции в объединении синтаксис нужно долго эти строки:

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 фильтруется, чтобы вернуть каждый рабочий день. S2 присоединяется к S1, где найдено совпадение. Это возвращает Mon, Tue, Wed и т. Д., Не возвращая Sat и Sun.

+0

Да, это он ... Мне просто нужно немного подкорректировать, чтобы исключить строки, которые представляют более одного дня (62 и 127). WHERE s2.DayId IN (1, 2, 4, 8, 16, 32, 64) – navossoc

+0

Как вы думаете, будет ли проще применять эту идею, если у меня есть несколько столбцов (по одному на каждый день), как вы сказали? – navossoc

+0

Ах да, я забыл, что 62 и 127 будут возвращены! Это зависит от того, где живет ваша логика. Если тяжелая работа происходит в интерфейсе, то, возможно, нет. Но если вы делаете все тяжелый подъем в SQL, тогда да, я бы сочетал с битовыми полями для более простой фильтрации. Что-то вроде * WHERE IsMonday = 1 * легче читать/писать/следовать, чем * Day & Day = 1 *. –

 Смежные вопросы

  • Нет связанных вопросов^_^