2016-07-19 5 views
0

У меня есть TABLE1сервер 2012 SQL: Перемещение столбцов на основе логики

(Payee_ID INT, 
BOX1 VARCHAR(2) NULL, -- possible value only AA 
BOX2 VARCHAR(2) NULL, -- possible value only BB 
BOX3 VARCHAR(2) NULL, -- possible value only CC 
BOX4 VARCHAR(2) NULL) -- possible value only DD 

TABLE1 значение:

1, NULL, ‘BB’, NULL, ‘DD’ 
2, ‘AA’, NULL, NULL, ‘DD’ 
3, NULL, ‘BB’, ‘CC’, ‘DD’ 
4, ‘AA’, ‘BB’, NULL, ‘DD’ 
5, ‘AA’, ‘BB’, ‘CC’, ‘DD’ and so on.. 

я создал еще один таблица2

(Payee_ID INT, 
BOX1 VARCHAR(2), --AA 
BOX2 VARCHAR(2), --BB 
BOX3 VARCHAR(2), --CC 
BOX4 VARCHAR(2)) --DD 

Теперь заселить эту таблицу используя таблицу 1, но правило заключается в том, что если Box1 имеет значение null, то используйте значение Box2 для Box1 и т. д. Таким образом, ожидаемый результат:

Payee_ID  Box1 Box2 Box3 Box4 
1,    ‘BB’, ‘DD’, ’’ ,  ’’ 
2,    ‘AA’, ‘DD’, ’’ ,  ’’ 
3,    ‘BB’, ‘CC’, ‘DD’, ‘’ 
4,    ‘AA’, ‘BB’, ‘DD’, ‘’ 
5,    ‘AA’, ‘BB’, ‘CC’, ‘DD’ 
+3

Это звучит как то, что вы должны делать на уровне представления, а не в базе данных –

+0

Для Payee_ID-почему BOX4 пустой? Разве это не DD? и не будет ли Box3 быть DD? – scsimon

+0

@scsimon: Нет, это то, что нужно. Если предыдущие поля пусты, переместите данные из столбцов, где у нас есть данные. поэтому для payee1, поскольку box1 равен null, а box2 - BB, BB перемещается в box1 и т. д. – user3294322

ответ

0

Проверить это ... хотя я все еще думаю, что вы не должны делать это в БД

IF OBJECT_ID('tempdb..#thisTest') IS NOT NULL DROP TABLE #thisTest 

SELECT 
1 as ID, NULL as BOX1, 'BB' as BOX2, NULL as BOX3, 'DD' as BOX4 
INTO #thisTest 
UNION ALL 
SELECT 
2, 'AA', NULL, NULL, 'DD' 
UNION ALL 
SELECT 
3, NULL, 'BB', 'CC', 'DD' 
UNION ALL 
SELECT 
4, 'AA', 'BB', NULL, 'DD' 
UNION ALL 
SELECT 
5, 'AA', 'BB', 'CC', 'DD' 


SELECT * from #thisTest 
select 
ID, 
CASE WHEN BOX1 IS NULL THEN COALESCE(BOX2,BOX3,BOX4) ELSE BOX1 END AS BOX1, 
CASE WHEN BOX1 IS NULL AND BOX2 IS NULL THEN BOX4 WHEN BOX1 IS NULL THEN COALESCE(BOX3,BOX4) ELSE COALESCE(BOX2,BOX3,BOX4) END AS BOX2, 
CASE WHEN BOX1 IS NULL AND BOX2 IS NULL THEN NULL WHEN (BOX1 IS NULL OR BOX2 IS NULL) and BOX3 IS NULL THEN NULL WHEN BOX1 IS NULL OR BOX2 IS NULL THEN COALESCE(BOX3,BOX4) ELSE BOX4 END AS BOX3, 
CASE WHEN BOX1 IS NULL or BOX2 IS NULL OR BOX3 IS NULL THEN NULL ELSE BOX4 END AS BOX4 
from 
#thisTest 
+0

Это просто демонстрирует, какую ужасную идею это нужно делать в базе данных. Он близок, но не дает желаемого результата. Посмотрите на payee_ID 5. :) –

+0

Добавьте следующие данные в таблицу, и ваш код дает корректные результаты: UNION ALL SELECT 6, NULL, NULL, 'CC', 'DD' – user3294322

+0

Payee_ID 5 действительно правильный! Проблема заключается в том, что вы добавляете payee_ID 6 с вышеуказанной комбинацией. – user3294322

0
IF OBJECT_ID('tempdb..#thisTest') IS NOT NULL DROP TABLE #thisTest 

SELECT 
1 as ID, NULL as BOX1, 'BB' as BOX2, NULL as BOX3, 'DD' as BOX4 
INTO #thisTest 
UNION ALL 
SELECT 
2, 'AA', NULL, NULL, 'DD' 
UNION ALL 
SELECT 
3, NULL, 'BB', 'CC', 'DD' 
UNION ALL 
SELECT 
4, 'AA', 'BB', NULL, 'DD' 
UNION ALL 
SELECT 
5, 'AA', 'BB', 'CC', 'DD' 
UNION ALL 
SELECT 6, NULL, NULL, 'CC', 'DD' 

SELECT * from #thisTest 
select 
ID, 
CASE WHEN BOX1 IS NULL THEN COALESCE(BOX2,BOX3,BOX4) ELSE BOX1 END AS BOX1, 

CASE WHEN BOX1 IS NULL AND BOX2 IS NOT NULL THEN COALESCE(BOX3,BOX4) 
    WHEN BOX1 IS NULL AND BOX2 IS NULL THEN BOX4 
    ELSE COALESCE(BOX2,BOX3,BOX4) END AS BOX2, 

CASE WHEN BOX1 IS NULL AND BOX2 IS NULL AND BOX3 IS NULL THEN BOX4 
    WHEN BOX1 IS NOT NULL AND BOX2 IS NOT NULL THEN COALESCE(BOX3,BOX4) 
    ELSE '' END AS BOX3, 

CASE WHEN BOX1 IS NOT NULL AND BOX2 IS NOT NULL AND BOX3 IS NOT NULL THEN BOX4 ELSE '' END AS BOX4 

from 
#thisTest 
+0

Это работало? Я оставил работу, поэтому не могу проверить – scsimon

+0

@scsimon Да, это так .. Спасибо :) – user3294322

+0

Рад, что я смог помочь. Я рад, что получил его в основном правильно и был полезным – scsimon

0

Я просто предположить #thisTest таблица заполняется так, как в приведенных выше примерах. Не нужно дублировать этот код.

WITH workTable as (
    SELECT 
     ID, 
     ISNULL(BOX1, '') + ISNULL(BOX2, '') + ISNULL(BOX3, '') + ISNULL(BOX4, '') AS Boxes 
    FROM #thisTest 
    ) 
INSERT INTO Table2 (
    Payee_id, 
    Box1, 
    Box2, 
    Box3, 
    Box4, 
    ) 
SELECT 
    ID, 
    ISNULL(SUBSTRING(Boxes, 1, 1), ''), 
    ISNULL(SUBSTRING(Boxes, 2, 1), ''), 
    ISNULL(SUBSTRING(Boxes, 3, 1), ''), 
    ISNULL(SUBSTRING(Boxes, 4, 1), '') 
FROM workTable 

Наша философия кодирования включает в себя простоту кода. Если бы это было на порядок медленнее, чем другие параметры, я бы не использовал его, но если нет, это будет выполнять то, что вам нужно, без нескольких проверок, какие значения BOXn равны нулю.

Обратите внимание, что эта базовая форма работает с небольшими изменениями, даже если у вас есть 20 значений BOX для компактности, тогда как логика проверки нескольких условий будет экспоненциально расти.

0

@ Laughing.Vergil находится на правильном пути, даже если его синтаксис откусил;)

Пока не отвечал ваш вопрос, я отвечу на этот вопрос, используя CTE один раз в JOIN себя, а также непосредственно , :D

Если вы правильно поняли, вы хотите, чтобы все значения были сдвинуты с левой стороны строки со всеми значениями NULL вправо. Я предпочел бы принять идею @ Laughing.Vergil, поскольку, если известные значения являются стабильной длиной, нет причин, по которым код должен быть ужасно сложным. т.е. LEN(Box1) = 2

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

CREATE TABLE #Example (Payee_ID INT, 
          BOX1 VARCHAR(2) NULL, 
          BOX2 VARCHAR(2) NULL, 
          BOX3 VARCHAR(2) NULL, 
          BOX4 VARCHAR(2) NULL) 
INSERT INTO #Example(Payee_ID, BOX1, BOX2, BOX3, BOX4) 
VALUES (1, NULL, 'BB', NULL, 'DD') 
     , (2, 'AA', NULL, NULL, 'DD') 
     , (3, NULL, 'BB', 'CC', 'DD') 
     , (4, 'AA', 'BB', NULL, 'DD') 
     , (5, 'AA', 'BB', 'CC', 'DD') 
     , (6, NULL, 'CB', NULL, 'DD') -- the bad input 
;WITH C as (
    SELECT 
     Payee_ID 
     , ISNULL(Box1, '') + ISNULL(Box2, '') + ISNULL(Box3, '') + ISNULL(Box4, '') AS BOX 
    FROM #Example 
    ) 
UPDATE A 
    SET 
    BOX1 = IIF(SUBSTRING(Box, 1, 2) = '', NULL, SUBSTRING(Box, 1, 2)) 
    , BOX2 = IIF(SUBSTRING(Box, 3, 2) = '', NULL, SUBSTRING(Box, 3, 2)) 
    , BOX3 = IIF(SUBSTRING(Box, 5, 2) = '', NULL, SUBSTRING(Box, 5, 2)) 
    , BOX4 = IIF(SUBSTRING(Box, 7, 2) = '', NULL, SUBSTRING(Box, 7, 2)) 
FROM #Example A 
INNER JOIN C ON C.Payee_ID = A.Payee_ID 

Результаты

Payee_ID BOX1 BOX2 BOX3 BOX4 
1   BB  DD  NULL NULL 
2   AA  DD  NULL NULL 
3   BB  CC  DD  NULL 
4   AA  BB  DD  NULL 
5   AA  BB  CC  DD 
6   CB  ED  NULL NULL 

Теперь захватывающая часть. Обновление/удаление из таблицы с использованием CTE s. Для аргументов, давайте предположим, что только первый ящик может быть некорректным из-за того, как работает приложение.

WITH CTE AS (SELECT * 
      FROM #Example2 
      WHERE BOX1 NOT IN ((LEFT(Box1, 1)) 
           + (LEFT(Box1, 1)))) 
DELETE FROM CTE 

Окончательные результаты

Payee_ID BOX1 BOX2 BOX3 BOX4 
1   BB  DD  NULL NULL 
2   AA  DD  NULL NULL 
3   BB  CC  DD  NULL 
4   AA  BB  DD  NULL 
5   AA  BB  CC  DD 

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

Приветствие,

+0

Обратите внимание, что я также предполагал, что Payee_ID имеет только одну связанную строку. –