我如何破解这个非 ansi 代码 blob

Ann*_*tta 4 sql-server sql-standard

大约一个月前,我刚刚开始了一份新工作,为一家人手不足的软件公司工作。我的任务是对一些旧的非 ansi SQL 代码进行现代化改造,我在尝试破解这个问题时遇到了特别困难的时间。我最近刚毕业,所以我对现代 SQL 标准有点熟悉,并且根据我所做的研究,不推荐使用的部分与非 ansi 连接 *= 相关。我已经尝试了几乎所有我能想到的改变这个烂摊子的方法,但我不知所措。谢谢你的协助。

Select @SQLCmd = 
'SELECT ''' + @InvType + ''' AS Inv_Type, ' + @TableName + '_Number AS     Item_Number, Alternate_ID, Description1, ' +
    'Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, ' +
    'Location_Current, Location_Home, Hold_Status, Record_Type,   Disposition_Status, ' + @TableName + '.Retention_Code, ' +
    'Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status ' +
'FROM ' + @TableName + ', RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS ' +
'Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV ' +
'WHERE ' + @TableName + '.Retention_Code *= RETENTION.Retention_Code AND ' +
    @TableName + '_Number *= RESV.Item_Number AND ''' + @InvType + ''' = RESV.Item_Type ' +
Case LTrim(@RetnType)
    When '' Then ''
    Else 'AND ' + @TableName + '.Retention_Type = ''' + @RetnType + ''''
End
+ ' AND ' + @WhereCond +
' UNION ' + 
'SELECT ''' + @InvType + ''' AS Inv_Type, ' + @TableName + '_Number AS Item_Number, Alternate_ID, Description1, ' +
    'Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, ' +
    'Location_Current, Location_Home, Hold_Status, Record_Type, Disposition_Status, ' + @TableName + '.Retention_Code, ' +
    'Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status ' +
'FROM ' + @TableName + ', RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS ' +
'Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV ' +
'WHERE ' + @TableName + '.Retention_Code *= RETENTION.Retention_Code AND ' +
    @TableName + '_Number *= RESV.Item_Number AND ''' + @InvType + ''' = RESV.Item_Type ' +
Case LTrim(@RetnType)
    When '' Then ''
    Else 'AND ' + @TableName + '.Retention_Type = ''' + @RetnType + ''''
End
Run Code Online (Sandbox Code Playgroud)

Han*_*non 8

考虑这两个简单的表:

CREATE TABLE dbo.t1
(
    t1_ID int NOT NULL
);

CREATE TABLE dbo.t2
(
    t2_ID int NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

JOINsSQL Server 2000 及更早版本中使用的“旧样式” ,如下所示:

SELECT *
FROM dbo.t1
    , dbo.t2
WHERE t1.t1_ID *= t2.t2_ID;
Run Code Online (Sandbox Code Playgroud)

等效于 ANSI 样式LEFT JOIN

SELECT *
FROM dbo.t1 
    LEFT JOIN dbo.t2 ON t1.t1_ID = t2.t2_ID;
Run Code Online (Sandbox Code Playgroud)

这个:

SELECT *
FROM dbo.t1
    , dbo.t2
WHERE t1.t1_ID =* t2.t2_ID;
Run Code Online (Sandbox Code Playgroud)

变成:

SELECT *
FROM dbo.t1 
    RIGHT JOIN dbo.t2 ON t1.t1_ID = t2.t2_ID;
Run Code Online (Sandbox Code Playgroud)

虽然,我不喜欢使用RIGHT JOIN,并且会将其重写为等效的LEFT JOIN,如下所示:

SELECT *
FROM dbo.t2 
    LEFT JOIN dbo.t1 ON t2.t2_ID = t1.t1_ID;
Run Code Online (Sandbox Code Playgroud)

您问题中的动态 SQL 足够复杂,我首先使用它PRINT来打印生成代码的示例,然后我将使用上述规则将旧样式连接转换为符合 ANSI 标准的连接。

我从你的代码中模拟了以下内容,试图简化它:

DECLARE @SQLCmd nvarchar(max);
DECLARE @InvType nvarchar(100) = 'InvType';
DECLARE @TableName nvarchar(128) = 'TableName';
DECLARE @RetnType nvarchar(100) = 'RetnType';
DECLARE @WhereCond nvarchar(1000) = 'WhereCond';

Select @SQLCmd = 
'SELECT ''' + @InvType + ''' AS Inv_Type, ' + @TableName + '_Number AS     Item_Number, Alternate_ID, Description1, 
    Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, 
    Location_Current, Location_Home, Hold_Status, Record_Type,   Disposition_Status, ' + @TableName + '.Retention_Code, 
    Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status 
FROM ' + @TableName + ', RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS 
Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV 
WHERE ' + @TableName + '.Retention_Code *= RETENTION.Retention_Code AND ' +
    @TableName + '_Number *= RESV.Item_Number AND ''' + @InvType + ''' = RESV.Item_Type 
    ' +
Case LTrim(@RetnType)
    When '' Then ''
    Else 'AND ' + @TableName + '.Retention_Type = ''' + @RetnType + ''''
End
+ ' 
    AND ' + @WhereCond +
' UNION 
SELECT ''' + @InvType + ''' AS Inv_Type, ' + @TableName + '_Number AS Item_Number, Alternate_ID, Description1, 
    Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, 
    Location_Current, Location_Home, Hold_Status, Record_Type, Disposition_Status, ' + @TableName + '.Retention_Code, 
    Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status 
FROM ' + @TableName + ', RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS 
Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV 
WHERE ' + @TableName + '.Retention_Code *= RETENTION.Retention_Code AND 
' + @TableName + '_Number *= RESV.Item_Number AND ''' + @InvType + ''' = RESV.Item_Type 
' +
Case LTrim(@RetnType)
    When '' Then ''
    Else 'AND ' + @TableName + '.Retention_Type = ''' + @RetnType + ''''
End

PRINT @SQLCmd;
Run Code Online (Sandbox Code Playgroud)

这导致:

SELECT 'InvType' AS Inv_Type, TableName_Number AS     Item_Number, Alternate_ID, Description1, 
    Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, 
    Location_Current, Location_Home, Hold_Status, Record_Type,   Disposition_Status, TableName.Retention_Code, 
    Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status 
FROM TableName, RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS 
Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV 
WHERE TableName.Retention_Code *= RETENTION.Retention_Code AND TableName_Number *= RESV.Item_Number AND 'InvType' = RESV.Item_Type 
    AND TableName.Retention_Type = 'RetnType' 
    AND WhereCond UNION 
SELECT 'InvType' AS Inv_Type, TableName_Number AS Item_Number, Alternate_ID, Description1, 
    Company_ID, Department_ID, Group_Id, Section_Id, Media_Code, 
    Location_Current, Location_Home, Hold_Status, Record_Type, Disposition_Status, TableName.Retention_Code, 
    Retn_Disposal_Method, Retn_Authorize_Code, Reservation_Status 
FROM TableName, RETENTION, (SELECT Item_Type, Item_Number, MAX(Reservation_Process_Status) AS 
Reservation_Status FROM RESERVATION GROUP BY Item_Type, Item_Number) AS RESV 
WHERE TableName.Retention_Code *= RETENTION.Retention_Code AND 
TableName_Number *= RESV.Item_Number AND 'InvType' = RESV.Item_Type 
AND TableName.Retention_Type = 'RetnType'
Run Code Online (Sandbox Code Playgroud)

我会重新格式化,以便每一列都在单独的行上:

SELECT 'InvType' AS Inv_Type
    , TableName_Number AS     Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , TableName.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM TableName
    , RETENTION
    , (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type, Item_Number
        ) AS RESV 
WHERE TableName.Retention_Code *= RETENTION.Retention_Code 
    AND TableName_Number *= RESV.Item_Number 
    AND 'InvType' = RESV.Item_Type 
    AND TableName.Retention_Type = 'RetnType' 
    AND WhereCond 
UNION 
SELECT 'InvType' AS Inv_Type
    , TableName_Number AS Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , TableName.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM TableName
    , RETENTION
    , (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type
            , Item_Number
        ) AS RESV 
WHERE TableName.Retention_Code *= RETENTION.Retention_Code 
    AND TableName_Number *= RESV.Item_Number 
    AND 'InvType' = RESV.Item_Type 
    AND TableName.Retention_Type = 'RetnType'
Run Code Online (Sandbox Code Playgroud)

有点乏味,但现在我们可以看到查询实际做了什么。

将“旧式”连接转换为 ANSI 式连接会导致:

SELECT 'InvType' AS Inv_Type
    , TableName_Number AS     Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , TableName.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM TableName
    LEFT JOIN RETENTION ON TableName.Retention_Code = RETENTION.Retention_Code
    LEFT JOIN (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type, Item_Number
        ) AS RESV ON TableName_Number = RESV.Item_Number 
WHERE 'InvType' = RESV.Item_Type 
    AND TableName.Retention_Type = 'RetnType' 
    AND WhereCond 
UNION 
SELECT 'InvType' AS Inv_Type
    , TableName_Number AS Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , TableName.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM TableName
    LEFT JOIN RETENTION ON TableName.Retention_Code = RETENTION.Retention_Code 
    LEFT JOIN (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type
            , Item_Number
        ) AS RESV ON TableName_Number = RESV.Item_Number  
WHERE 'InvType' = RESV.Item_Type 
    AND TableName.Retention_Type = 'RetnType'
Run Code Online (Sandbox Code Playgroud)

将其折叠回动态 SQL 会导致:

DECLARE @SQLCmd nvarchar(max);
DECLARE @TableName nvarchar(128);
DECLARE @InvType nvarchar(100);
DECLARE @RetnType nvarchar(100);
DECLARE @WhereCond nvarchar(1000);

SET @SQLCmd = 'SELECT ''' + @InvType + ''' AS Inv_Type
    , TableName_Number AS     Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , TableName.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM ' + @TableName + '
    LEFT JOIN RETENTION ON ' + @TableName + '.Retention_Code = RETENTION.Retention_Code
    LEFT JOIN (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type, Item_Number
        ) AS RESV ON TableName_Number = RESV.Item_Number 
WHERE ' + @InvType + ' = RESV.Item_Type 
    AND ' + @TableName + '.Retention_Type = ''' + @RetnType + ''' 
    AND ' + @WhereCond + '
UNION 
SELECT ''' + @InvType + ''' AS Inv_Type
    , ' + @TableName + '_Number AS Item_Number
    , Alternate_ID
    , Description1
    , Company_ID
    , Department_ID
    , Group_Id
    , Section_Id
    , Media_Code
    , Location_Current
    , Location_Home
    , Hold_Status
    , Record_Type
    , Disposition_Status
    , ' + @TableName + '.Retention_Code
    , Retn_Disposal_Method
    , Retn_Authorize_Code
    , Reservation_Status 
FROM ' + @TableName + '
    LEFT JOIN RETENTION ON ' + @TableName + '.Retention_Code = RETENTION.Retention_Code 
    LEFT JOIN (
        SELECT Item_Type
            , Item_Number
            , MAX(Reservation_Process_Status) AS Reservation_Status 
        FROM RESERVATION 
        GROUP BY Item_Type
            , Item_Number
        ) AS RESV ON ' + @TableName + '_Number = RESV.Item_Number  
WHERE ''' + @InvType + ''' = RESV.Item_Type 
    AND TableName.Retention_Type = ''' + @RetnType + ''''
Run Code Online (Sandbox Code Playgroud)