SQL 2005 оператор SELECT CASE <column> - PullRequest
0 голосов
/ 31 января 2009

Я был бы очень признателен за помощь, я серьезно застрял. В основном у меня есть таблица, которая

выглядит так:

SSS_DOWID Name Mon  Tue  Wed  Thu   Fri   Sat   Sun   Description  
2         M    Y    N    N    N     N     N     N     Monday
3         MF   Y    N    N    N     Y     N     N     Monday, Friday
.......
18        T    N    Y    N    N     N     N     N     Tuesday
........
etc.

Что мне нужно сделать, это преобразовать значения в этой таблице в таблицу, которая содержит только

соответствующие номера для дней недели, например, 1 в воскресенье, 2 в понедельник, 3 во вторник и т. д., вплоть до 8 в воскресенье.

ТАК У меня есть немного SQL:

DECLARE @strDays table
(SSS_DOWID int)

INSERT INTO @strDays
SELECT  
  case (sun) when 'Y' then '1' else '' end +  
  case (mon) when 'Y' then '2' else '' end +   
  case (tue) when 'Y' then '3' else '' end +  
  case (wed) when 'Y' then '4' else '' end +   
  case (thu) when 'Y' then '5' else '' end +  
  case (fri) when 'Y' then '6' else '' end +   
  case (sat) when 'Y' then '7' else '' end  
 FROM   
  [dbo].SSS_DOW  WITH (NOLOCK)  
 WHERE  
  SSS_DOWID IN (28,41,44)  

SELECT * FROM @strDays

Который отлично работает для отдельных дней, КРОМЕ дневных комбинаций. Так что в этом случае, когда я перехожу в

28 (ср.), 41 (пт) и 44 (SaSun), я получаю 4 (идеально), 6 (идеально) и 17 (о, дерьмо - должно быть

1 и 7, отдельно).

Может кто-нибудь помочь мне реструктурировать мой SQL, чтобы я получил таблицу, содержащую 1, 4, 6 и 7 вместо

из 4, 6, 17?

Ответы [ 6 ]

2 голосов
/ 31 января 2009

Похоже, вам нужен разворот.

DECLARE @Days TABLE
(
  DayId int PRIMARY KEY,
  found int
)

INSERT INTO @Days(DayId, found) SELECT 1, 0
INSERT INTO @Days(DayId, found) SELECT 2, 0
INSERT INTO @Days(DayId, found) SELECT 3, 0
INSERT INTO @Days(DayId, found) SELECT 4, 0
INSERT INTO @Days(DayId, found) SELECT 5, 0
INSERT INTO @Days(DayId, found) SELECT 6, 0
INSERT INTO @Days(DayId, found) SELECT 7, 0
--
UPDATE d
SET d.found = 1
FROM  @Days d JOIN SSS_DOW s
  ON 
 CASE
    WHEN d.DayId = 1 and s.Mon == 'Y' THEN 1
    WHEN d.DayId = 2 and s.Tue == 'Y' THEN 1
    WHEN d.DayId = 3 and s.Wed == 'Y' THEN 1
    WHEN d.DayId = 4 and s.Thu == 'Y' THEN 1
    WHEN d.DayId = 5 and s.Fri == 'Y' THEN 1
    WHEN d.DayId = 6 and s.Sat == 'Y' THEN 1
    WHEN d.DayId = 7 and s.Sun == 'Y' THEN 1
    ELSE 0
  END = 1
WHERE SSS_DowID in (28, 41, 44)
--
SELECT *
FROM @Days
WHERE found = 1
1 голос
/ 01 февраля 2009

В SQL Server 2005 вы можете использовать явное UNPIVOT:

/*
CREATE TABLE SSS_DOW (
    SSS_DOWID int NOT NULL
    ,[Name] varchar(50) NOT NULL
    ,Mon char(1) NOT NULL
    ,Tue char(1) NOT NULL
    ,Wed char(1) NOT NULL
    ,Thu char(1) NOT NULL
    ,Fri char(1) NOT NULL
    ,Sat char(1) NOT NULL
    ,Sun Char(1) NOT NULL
    ,[Description] varchar(50) NOT NULL
)

INSERT INTO SSS_DOW VALUES (2, 'M', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 'Monday')
INSERT INTO SSS_DOW VALUES (3, 'MF', 'Y', 'N', 'N', 'N', 'Y', 'N', 'N', 'Monday, Friday')
INSERT INTO SSS_DOW VALUES (28, 'W', 'N', 'N', 'Y', 'N', 'N', 'N', 'N', 'Wednesday')
INSERT INTO SSS_DOW VALUES (41, 'F', 'N', 'N', 'N', 'N', 'Y', 'N', 'N', 'Friday')
INSERT INTO SSS_DOW VALUES (44, 'SaSun', 'N', 'N', 'N', 'N', 'N', 'Y', 'Y', 'Satruday, Sunday')
*/

;WITH DateAbbrev AS (
    SELECT number, LEFT(DATENAME(dw, number - 2), 3) AS abbrev
    FROM master..spt_values
    WHERE type = 'P'
        AND number BETWEEN 1 AND 7
)
SELECT SSS_DOWID, DateAbbrev.number AS DayOfWeek
FROM SSS_DOW
UNPIVOT (Flag FOR dow IN ([Mon], [Tue], [Wed], [Thu], [Fri], [Sat], [Sun])) AS pvt
INNER JOIN DateAbbrev
    ON DateAbbrev.abbrev = dow
WHERE Flag = 'Y'
    AND SSS_DOWID IN (28, 41, 44)

/*
DROP TABLE SSS_DOW
*/

Если у вас уже есть таблица сокращений дат, вы можете присоединиться к ней вместо специального CTE, который я использовал для ее создания.

1 голос
/ 01 февраля 2009

Мне кажется, ты цитируешь свои цифры:

case (sun) when 'Y' then '1' else '' end +  
case (mon) when 'Y' then '2' else '' end + 

Так что, когда вы используете '+', вы получаете конкатенацию вместо сложения. Вот почему вы получаете 17 в качестве ответа.

Что касается разбивки его на два отдельных ответа в столбце, вам, возможно, потребуется попробовать один из ответов, перечисленных здесь.

1 голос
/ 01 февраля 2009
WITH days AS (
    SELECT SSS_DOWID, 1 AS DayOfWeek FROM dbo.SSS_DOW WHERE sun = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 2 AS DayOfWeek FROM dbo.SSS_DOW WHERE mon = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 3 AS DayOfWeek FROM dbo.SSS_DOW WHERE tue = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 4 AS DayOfWeek FROM dbo.SSS_DOW WHERE wed = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 5 AS DayOfWeek FROM dbo.SSS_DOW WHERE thu = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 6 AS DayOfWeek FROM dbo.SSS_DOW WHERE fri = 'Y'
    UNION ALL
    SELECT SSS_DOWID, 7 AS DayOfWeek FROM dbo.SSS_DOW WHERE sat = 'Y')
SELECT DayOfWeek
FROM days
WHERE SSS_DOWID IN (28,41,44);
0 голосов
/ 13 февраля 2013

Попробуйте сделать это и дайте мне знать, если это не сработает.

DECLARE @strDays table
(SSS_DOWID int)

  INSERT INTO @strDays
 select substring(
 (SELECT  
 case (sun) when 'Y' then ',1' else '' end +  
 case (mon) when 'Y' then ',2' else '' end +   
 case (tue) when 'Y' then ',3' else '' end +  
 case (wed) when 'Y' then ',4' else '' end +   
 case (thu) when 'Y' then ',5' else '' end +  
 case (fri) when 'Y' then ',6' else '' end +   
  case (sat) when 'Y' then ',7' else '' end  
FROM   
  [dbo].SSS_DOW  WITH (NOLOCK)  
 WHERE  
 SSS_DOWID IN (28,41,44)  ),2,100)

SELECT * FROM @strDays
0 голосов
/ 01 февраля 2009

Попробуйте сделать семь операторов вставки:

INSERT INTO @strDays 
  SELECT SSS_DOWID, 1 FROM SSS_DOW WHERE SSS_DOWID IN (28,41,44) AND Sun = 'Y';


INSERT INTO @strDays 
  SELECT SSS_DOWID, 2 FROM SSS_DOW WHERE SSS_DOWID IN (28,41,44) AND Mon = 'Y';

etc.
...