2012-05-31 3 views
0

У меня есть таблица в SQL Server 2008, содержащая около 50 столбцов. Каждый из этих столбцов соответствует сканеру штрих-кода; у нас есть различные последовательные по IP-боксы вокруг разбросанных по всему предприятию. После получения сканирования небольшое приложение вставляет дату в относительное поле.SQL Server 2008 - динамически сопоставлять столбцы

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

Таким образом, вместо

UPDATE scans 
SET completed = 1 
WHERE (scanner_1 IS NOT NULL OR scanner_2 IS NOT NULL) 

... Я ищу, чтобы попытаться что-то вдоль линий

UPDATE scans 
SET completed = 1 
WHERE (/* Something to select all columns, maybe with an exclusion */ WHERE fields IS NOT NULL) 

Я надеюсь, что я объяснил это достаточно хорошо, спасибо для смотреть всем!


У нас есть таблица, в которой перечислены все сканеры и COM-порты, например.

id (PK) 
com_port 
scanner 

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

barcode_id (PK) 
scanner_1 
scanner_2 
scanner_3 
+7

Я хотел бы рассмотреть нормализации базы данных и не имеющие 1 поле для каждого сканера, вы добавив новое поле, когда вы получите новый сканер? –

+1

Я бы ожидал, что у каждого сканера есть какой-то уникальный идентификатор - правильно? Таким образом, вы должны иметь возможность нормализовать это в отдельную таблицу, которая будет содержать идентификатор сканера и столбец «завершен» ... –

+0

может у plz разместить структуру таблицы – Zia

ответ

1

Я, конечно же, согласен с комментариями относительно нормализации базы данных. В идеале вы должны иметь отдельную таблицу с внешними ключами, связанными с IP-окном и сканером.

Для облегчения нормализации данных вы можете посмотреть функцию UNPIVOT. Например.

CREATE TABLE T (ID INT NOT NULL, Scanner1 DATETIME, Scanner2 DATETIME, Scanner3 DATETIME, Scanner4 DATETIME) 

INSERT INTO T VALUES 
    (1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), 
    (2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL), 
    (3, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL), 
    (4, CURRENT_TIMESTAMP, NULL, NULL, NULL), 
    (5, NULL, NULL, NULL, NULL) 

SELECT ID, Scanner, ScannedDate 
FROM T 
     UNPIVOT 
     ( ScannedDate 
      FOR Scanner IN ([Scanner1], [Scanner2], [Scanner3], [Scanner4]) 
     ) UnPvt 
ORDER BY ID, Scanner 

который будет возвращать что-то вроде этого:

ID Scanner  ScannedDate 
----------------------------------- 
1 Scanner1 May 31 2012 10:40AM 
1 Scanner2 May 31 2012 10:40AM 
1 Scanner3 May 31 2012 10:40AM 
1 Scanner4 May 31 2012 10:40AM 
2 Scanner1 May 31 2012 10:40AM 
2 Scanner2 May 31 2012 10:40AM 
2 Scanner3 May 31 2012 10:40AM 
3 Scanner1 May 31 2012 10:40AM 
3 Scanner2 May 31 2012 10:40AM 
4 Scanner1 May 31 2012 10:40AM 

Это все еще имеет проблему того, чтобы выписывать столбцы вручную, однако вы можете динамически создать UNPIVOT заявление тоже:

DECLARE @SQL NVARCHAR(MAX) = '', 
     @Columns NVARCHAR(MAX) = '' 

SELECT @Columns = @Columns + ',' + QUOTENAME(Name) 
FROM SYS.COLUMNS 
WHERE OBJECT_ID = OBJECT_ID(N'T') 
AND  LEFT(Name, 7) = 'Scanner' 

SET @SQL = 'SELECT ID, Scanner, ScannedDate 
      FROM T 
        UNPIVOT 
        ( ScannedDate 
         FOR Scanner IN (' + STUFF(@Columns, 1, 1, '') + ') 
        ) UnPvt 
      ORDER BY ID, Scanner' 

DECLARE @UnPivot TABLE (ID INT, Scanner VARCHAR(50), ScannedDate DATETIME) 
INSERT INTO @UnPivot 
EXECUTE SP_EXECUTESQL @SQL 

SELECT * 
FROM @UnPivot 

Наконец, если вам нужно преобразовать нормализованные данные обратно в плоское представление, это все равно можно выполнить с помощью функции PIVOT (это предполагает @SQL и @Columns ar е уже определено выше):

CREATE TABLE ##UnPivot (ID INT, Scanner VARCHAR(50), ScannedDate DATETIME) 
INSERT INTO ##UnPivot 
EXECUTE SP_EXECUTESQL @SQL 

SELECT * 
FROM ##UnPivot 

SET @SQL = 'SELECT ID' + @Columns + ' 
      FROM ##Unpivot 
        PIVOT 
        ( MAX(ScannedDate) 
         FOR Scanner IN (' + STUFF(@Columns, 1, 1, '') + ') 
        ) UnPvt 
      ORDER BY ID' 

EXECUTE SP_EXECUTESQL @SQL 

DROP TABLE ##UnPivot 

Я поставил полный рабочий пример динамически unpivoting данные, а затем поворачиваясь снова на SQL Fiddle


EDIT

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

DECLARE @SQL NVARCHAR(MAX) = '', 
     @Columns NVARCHAR(MAX) = ' WHERE 1 = 1 ' 

SELECT @Columns = @Columns + 'AND ' + QUOTENAME(Name) + ' IS NOT NULL ' 
FROM SYS.COLUMNS 
WHERE OBJECT_ID = OBJECT_ID(N'T') 
AND  LEFT(Name, 7) = 'Scanner' 

SET @SQL = 'UPDATE T SET Completed = 1' + @Columns 
EXECUTE SP_EXECUTESQL @SQL 

Опять же, есть рабочий пример на SQL Fiddle

+0

Спасибо, это отлично! Я знаю о проблеме с нормализацией, нам дали набор данных из старой базы данных доступа, с которой мы работаем, при одновременной работе существующей системы; это внесет приятное изменение в схему для новой системы. Спасибо за вашу помощь и примеры! –

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