在不知道 table 中有什么的情况下映射列

Mapping columns without knowing what's in the table

我有一个奇怪的情况,我将有来自各种来源的数据(所有平面文件,其中 none 在我的控制之下,无论我要求多少次标准格式,我得到不同的列 headers 和不同的列顺序)。我们没有人力手动浏览这些文件来确定哪些列是重要的。每个平面文件将包含两到六个 "identification" 列。但是,有些列单独来看并不是唯一的,但它们的组合可以形成唯一的键。总而言之,每个平面文件可以有大约一百列。

因此,最初,我计划将数据加载到临时文件中 table 并要求用户确定哪些列包含哪些数据。一旦我知道了这一点,我就可以毫无问题地处理该文件。我会有两到六列来识别与现有记录的匹配项以及我应该收集的额外数据(全部由用户识别)。

然后我被要求为系统添加 "recommend" 哪些数据列是哪些的能力。为此,我的计划是一个计数。我会计算每列有多少个 nonempty 值,然后计算这些 nonempty 值中有多少与六个可能的列中的每一个相匹配。从那里,我可以采用一个简单的比率来确定所包含的数据属于该特定类型的可能性。对不是唯一的列会有一些高估,但总的来说,它运行良好。问题是速度很慢。

我创建了一个元数据 table,我称之为 UploadedTableColumn,其中包含源文件的每一列 header 以及它映射到数据库中的哪一列。这是我更新计数的存储过程:

CREATE PROCEDURE stored_Procedure 
    @FileLoadID INT
AS
BEGIN
    DECLARE @SqlCommand NVARCHAR(MAX)

    DECLARE the_cursor CURSOR FAST_FORWARD FOR 
    SELECT N'UPDATE UploadedTableColumn SET NumberNonemptyRows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberID1Rows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N','''') IN (SELECT ID1 FROM ID1Table) AND ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberID2Rows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N','''') IN (SELECT ID2 FROM ID2Table) AND ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberIDDateRows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE IIF(ISDATE(' + DestinationColumnName + N')=1,IIF(CAST(' + DestinationColumnName + N' AS DATE) IN (SELECT IDDate FROM IDDateTable),1,0),0) = 1 AND ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberID4Rows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N', '''') IN (SELECT ID4 FROM ID4Table) AND ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberID5Rows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N', '''') IN (SELECT ID5 FROM ID5Table) AND ISNULL(' + DestinationColumnName + N','''') <> ''''),' + CHAR(13)
        + N'NumberID6Rows = (SELECT COUNT(*) FROM ' + DestinationTableName + N' WHERE ISNULL(' + DestinationColumnName + N', '''') IN (SELECT ID6 FROM ID6Table) AND ISNULL(' + DestinationColumnName + N','''') <> '''')' + CHAR(13)
        + N'WHERE DestinationTableName = ''' + DestinationTableName + N''' AND DestinationColumnName = ''' + DestinationColumnName + N''' AND FileLoadID = ' + CAST(@FileLoadID AS NVARCHAR) + N';' + CHAR(13) As SqlCommand
    FROM UploadedTableColumn
    WHERE FileLoadID = @FileLoadID

    OPEN the_cursor

    FETCH NEXT FROM the_cursor
    INTO @SqlCommand

    WHILE @@FETCH_STATUS = 0
    BEGIN
        EXECUTE(@SqlCommand)

        FETCH NEXT FROM the_cursor 
        INTO @SqlCommand
    END

    CLOSE the_cursor
    DEALLOCATE the_cursor
END

有没有更快的方法?

一个小改动可能会有帮助。

您说您在 UploadedTableColumn 中保留了源 table 的每一列 - 您不需要这样做,您的光标会循环浏览很多不必要的列。您可以使用 pre-emptive 列名称匹配来消除很多。

因此,从您的 ID1Table、ID2Table 等中获取所有可能的 ID 列的组合列表,并且只将与 DestinationTableName 中的列实际匹配的列拉入 UploadedTableColumn。

基于您的源数据中可能不超过 6 列具有匹配的 ID 列名称,您现在只检查这些列而不是全部 100 多列。

当然,如果有人发送数据时没有 headers 且格式不一致,这对您没有帮助。

获取所需列的伪代码:

SELECT name
FROM sys.columns
WHERE [object_id] = OBJECT_ID('DestinationTableName')
AND Name IN
(
SELECT ID1 AS IDColumn FROM ID1Table
UNION ALL
SELECT ID2 AS IDColumn FROM ID2Table
...
)