0

SQL Server 2008 に、約 50 列を含むテーブルがあります。これらの各列は、バーコード スキャナーに対応しています。工場の周りには、さまざまなシリアルから IP へのボックスが散らばっています。スキャンを受信すると、小さなアプリケーションが相対フィールドに日付を挿入します。

私がやろうとしているのは、手動ですべてをリストすることなく、このテーブル内のフィールドを比較することです。理想的には、テーブルで実行される 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
4

1 に答える 1

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 が上記のように既に定義されていることを前提としています)。

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

データのピボットを動的に解除し、 SQL Fiddleで再度ピボットする完全な実例を掲載しました。


編集

元の質問に実際には答えていないことに気づきました。データを正規化する方法についてアドバイスしただけです。列を手動で入力せずにそれを行う方法は次のとおりです。

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には実用的な例があります

于 2012-05-31T09:56:57.467 に答える