即使CTE无法解决,也会返回结果

时间:2013-06-14 20:18:52

标签: sql-server tsql stored-procedures

我的SQL Server上有一个存储过程,它整合了一系列字段,以便在SSRS for Report Builder中使用。该过程由FileId提供,然后运行其逻辑。它按预期工作,直到文件无法找到或引用Solicitor和Arresting Officer字段。

即使fileId没有关联的逮捕官或律师,我也需要这个来返回结果。我确信这很简单。基本上,如果CTE从查询中返回任何内容,我仍然需要一个默认行。

 ALTER PROCEDURE [dbo].[GetRollCallData] 
    @Ids        VARCHAR(255),
    @LexiconId  INT,
    @UUID       UNIQUEIDENTIFIER,
    @ReadOnly   INT
 AS


 DECLARE @TableCode INT
 SET @TableCode = 58

 IF @Ids <> ''
    BEGIN
        EXEC InsertInSelectionCache @Ids, @UUID, @TableCode, 0
        IF @ReadOnly = 1
            WITH DOACTE AS(
            SELECT ROW_NUMBER() OVER(PARTITION BY [File].Id ORDER BY CustomRecordsetId DESC) AS RowNumber, [File].*, FileType2Lexicon.Label as FileTypeLabel, [People].DefaultPhone, [People].InvertedName, CustomField.Name as FieldLabel, CustomFieldValue.Value as FieldValue
                FROM FileType2Lexicon, SelectionCache, [People], [File]
                INNER JOIN [CustomRecordSet]
                ON [CustomRecordset].RecordId = [File].Id
                INNER JOIN CustomFieldValue
                ON  [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
                INNER JOIN [CustomField2Lexicon]
                ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
                INNER JOIN [CustomField]
                ON CustomField.Id = CustomField2Lexicon.CustomFieldId
                WHERE   [File].Id = SelectionCache.RecordId
                AND SelectionCache.UUID = @UUID
                AND SelectionCache.TableCode = @TableCode -- this is the code for File table  
                AND     [File].Id <> 0 
                AND     [File].FileTypeId = FileType2Lexicon.FileTypeId 
                AND     FileType2Lexicon.LexiconId = @LexiconId
                AND     [File].ClientIdString = [People].ClientIdString
                AND     CustomFieldValue.Value <> ''),

            SolicitorCTE AS(

                SELECT [People].Name AS SolicitorName, [File].Id
                FROM SelectionCache, [File]
                INNER JOIN [People2File]
                ON [People2File].FileId = [File].Id
                INNER JOIN [Role2Lexicon]
                ON [Role2Lexicon].RoleId = [People2File].RoleId
                INNER JOIN [People]
                ON [People].Id = [People2File].PeopleId
                WHERE 
                [File].Id = SelectionCache.RecordId
                AND SelectionCache.UUID = @UUID
                AND SelectionCache.TableCode = @TableCode -- this is the code for File table  
                AND [File].Id <> 0
                AND [Role2Lexicon].Label = 'Solicitor'),

             ArrestingOfficerCTE AS(
                SELECT ROW_NUMBER() OVER(PARTITION BY [File].Id ORDER BY [People].InvertedName ASC) AS RowNumber, [People].Name AS ArrestingOfficerName, [People].CompanyName AS ArrestingOfficerCompany, [File].Id
                FROM SelectionCache, [File]
                INNER JOIN [People2File]
                ON [People2File].FileId = [File].Id
                INNER JOIN [Role2Lexicon]
                ON [Role2Lexicon].RoleId = [People2File].RoleId
                INNER JOIN [People]
                ON [People].Id = [People2File].PeopleId
                WHERE 
                [File].Id = SelectionCache.RecordId
                AND SelectionCache.UUID = @UUID
                AND SelectionCache.TableCode = @TableCode -- this is the code for File table  
                AND [File].Id <> 0
                AND [Role2Lexicon].Label = 'Arresting Officer'),

            PivotCTE AS(
                SELECT *
                FROM
                (Select Id, FieldLabel, FieldValue FROM DOACTE) AS Source
                PIVOT(
                MAX(FieldValue) FOR FieldLabel IN ([Date_Arrest], [Graphic_Client], [Ticket_1], [Ticket_2], [Ticket_3], [Ticket_4], [Ticket_5], [Charge_1], [Charge_2], [Charge_3], [Charge_4], [Charge_5])) as Pvt
                )

            SELECT DOACTE.*, COALESCE(ArrestingOfficerCTE.ArrestingOfficerCompany, 'NULL')AS ArrestingOfficerCompany, COALESCE(ArrestingOfficerCTE.ArrestingOfficerName, 'NULL') AS ArrestingOfficerName, SolicitorCTE.SolicitorName, PivotCTE.[Date_Arrest], dbo.GetImagebyId(PivotCTE.[Graphic_Client]) as Photo, PivotCTE.[Ticket_1], PivotCTE.[Ticket_2], PivotCTE.[Ticket_3], PivotCTE.[Ticket_4], PivotCTE.[Ticket_5], PivotCTE.[Charge_1], PivotCTE.[Charge_2], PivotCTE.[Charge_3], PivotCTE.[Charge_4], PivotCTE.[Charge_5]
            FROM DOACTE
            INNER JOIN 
            PivotCTE
            ON DOACTE.Id = PivotCTE.Id
            INNER JOIN
            SolicitorCTE
            ON DOACTE.Id = SolicitorCTE.Id
            INNER JOIN
            ArrestingOfficerCTE
            ON DOACTE.Id = ArrestingOfficerCTE.Id
            WHERE DOACTE.RowNumber = 1
            AND ArrestingOfficerCTE.RowNumber = 1

        ELSE

        DELETE SelectionCache 
            WHERE UUID = @UUID
            AND   TableCode = @TableCode
    END

3 个答案:

答案 0 :(得分:1)

您可以保留联接以获取可选结果。我还需要为Arresting官员添加一个空检查到caluse的位置,这样即使是左连接,也不会排除记录。

SELECT DOACTE.*, COALESCE(ArrestingOfficerCTE.ArrestingOfficerCompany, 'NULL')AS ArrestingOfficerCompany, COALESCE(ArrestingOfficerCTE.ArrestingOfficerName, 'NULL') AS ArrestingOfficerName, SolicitorCTE.SolicitorName, PivotCTE.[Date_Arrest], dbo.GetImagebyId(PivotCTE.[Graphic_Client]) as Photo, PivotCTE.[Ticket_1], PivotCTE.[Ticket_2], PivotCTE.[Ticket_3], PivotCTE.[Ticket_4], PivotCTE.[Ticket_5], PivotCTE.[Charge_1], PivotCTE.[Charge_2], PivotCTE.[Charge_3], PivotCTE.[Charge_4], PivotCTE.[Charge_5]
            FROM DOACTE
            INNER JOIN 
            PivotCTE
            ON DOACTE.Id = PivotCTE.Id
            LEFT JOIN
            SolicitorCTE
            ON DOACTE.Id = SolicitorCTE.Id
            LEFT JOIN
            ArrestingOfficerCTE
            ON DOACTE.Id = ArrestingOfficerCTE.Id
            WHERE DOACTE.RowNumber = 1
            AND ( ArrestingOfficerCTE.RowNumber = 1 or ArrestingOfficerCTE.RowNumber is null )

答案 1 :(得分:0)

你可以尝试:

SELECT DOACTE.*, COALESCE(ArrestingOfficerCTE.ArrestingOfficerCompany, 'NULL')AS ArrestingOfficerCompany, COALESCE(ArrestingOfficerCTE.ArrestingOfficerName, 'NULL') AS ArrestingOfficerName, SolicitorCTE.SolicitorName, PivotCTE.[Date_Arrest], dbo.GetImagebyId(PivotCTE.[Graphic_Client]) as Photo, PivotCTE.[Ticket_1], PivotCTE.[Ticket_2], PivotCTE.[Ticket_3], PivotCTE.[Ticket_4], PivotCTE.[Ticket_5], PivotCTE.[Charge_1], PivotCTE.[Charge_2], PivotCTE.[Charge_3], PivotCTE.[Charge_4], PivotCTE.[Charge_5]
into #Results
            FROM DOACTE
            INNER JOIN 
            PivotCTE
            ON DOACTE.Id = PivotCTE.Id
            INNER JOIN
            SolicitorCTE
            ON DOACTE.Id = SolicitorCTE.Id
            INNER JOIN
            ArrestingOfficerCTE
            ON DOACTE.Id = ArrestingOfficerCTE.Id
            WHERE DOACTE.RowNumber = 1
            AND ArrestingOfficerCTE.RowNumber = 1

if ((select cout(*) from #Results) = 0)
begin

insert into #Results
      select
           .......your default values......

end

select * from #Results

drop table #Results

答案 2 :(得分:0)

这几乎是谎言19的回答,所以我在他第一次到达那里后就投了赞成票。我认为答案归结为LEFT JOIN你所在的INNER。由于我重新编写了您的查询,因此我实际上可以理解发生了什么,并且我做了一些您可能想要或可能不想要的更改,所以我会留在这里,以防它有用。

我的线路比你的更多,因为我的格式不同,部分是因为我使用临时表做了4次你做的事情。关于CTE的是,当你像这样堆叠它们时,你可能会得到一些非常粗糙的表现。 CTE的行为基本上就像一个即时视图,他们的SQL几乎在所有地方都重复出现。我正在限制[File]并将其移动到临时表中。然后我将它转换为另一个(因为这进一步限制了基于RowNumber1的内容。然后我只使用最后的2个CTE并将其用于最终结果。

最后,SELECT * ...是邪恶的。我只是在寻找某些东西时才使用它。将它放入像这样的sproc会导致你的问题,如架构或CTE等等的变化。当你制作一个sproc,命名每一列时,它将在未来咬你更少。

如果您觉得它没有用,请随时忽略:

ALTER PROCEDURE [dbo].[GetRollCallData] 
    @Ids        VARCHAR(255),
    @LexiconId  INT,
    @UUID       UNIQUEIDENTIFIER,
    @ReadOnly   INT
AS
BEGIN
    DECLARE @TableCode INT = 58;

    IF @Ids <> ''
    BEGIN
        EXEC InsertInSelectionCache @Ids, @UUID, @TableCode, 0

        IF @ReadOnly = 1
        BEGIN
            SELECT
                -- Add any other fully qualified columns. * is evil for sprocs. Only good for poking around in your own queries.
                AllFiles.Id
            INTO #SelectionFile
            FROM 
                [File] AllFiles
                INNER JOIN SelectionCache Cache
                    ON Cache.RecordId = AllFiles.Id
                    AND Cache.UUID = @UUID
                    AND Cache.TableCode = @TableCode -- this is the code for File table 
            WHERE
                AllFiles.Id <> 0

            ;WITH DOACTE AS
            (
                SELECT 
                    ROW_NUMBER() OVER(PARTITION BY SelectionFile.Id ORDER BY CustomRecordsetId DESC) AS RowNumber
                    , SelectionFile.Id AS FileId
                    -- [Replace with any other columns that you selected from [File] at the top.]
                    , Lexicon.Label AS FileTypeLabel
                    , [People].DefaultPhone
                    , [People].InvertedName
                    , CustomField.Name AS FieldLabel
                    , CustomFieldValue.Value AS FieldValue
                FROM 
                    #SelectionFile SelectionFile
                    INNER JOIN FileType2Lexicon Lexicon
                        ON Lexicon.FileTypeId = SelectionFile.FileTypeId
                        AND Lexicon.LexiconId = @LexiconId
                    INNER JOIN [People]
                        ON [People].ClientIdString = SelectionFile.ClientIdString
                    INNER JOIN [CustomRecordSet]
                        ON [CustomRecordset].RecordId = SelectionFile.Id
                    INNER JOIN CustomFieldValue
                        ON [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
                        AND CustomFieldValue.Value <> ''
                    INNER JOIN [CustomField2Lexicon]
                        ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
                    INNER JOIN [CustomField]
                        ON CustomField.Id = CustomField2Lexicon.CustomFieldId
            )
            SELECT 
                Pvt.FileId
                -- [Replace with any other columns that you selected from DOACTE you want to propagate to the end.]
                , Pvt.[Date_Arrest]
                , Pvt.[Graphic_Client]
                , Pvt.[Ticket_1]
                , Pvt.[Ticket_2]
                , Pvt.[Ticket_3]
                , Pvt.[Ticket_4]
                , Pvt.[Ticket_5]
                , Pvt.[Charge_1]
                , Pvt.[Charge_2]
                , Pvt.[Charge_3]
                , Pvt.[Charge_4]
                , Pvt.[Charge_5]
            INTO #PivotedFile
            FROM
            (
                SELECT 
                    FileId
                    -- [Replace with any other columns that you selected from DOACTE you want to propagate to the end.]
                    , FieldLabel
                    , FieldValue 
                    , FieldLabel AS PivotFieldLabel
                    , FieldValue AS PivotFieldValue
                FROM 
                    DOACTE
                WHERE 
                    RowNumber = 1
            ) AS Source
            PIVOT
            (
                MAX(PivotFieldValue) 
                FOR PivotFieldLabel 
                IN 
                (
                    [Date_Arrest]
                    , [Graphic_Client]
                    , [Ticket_1]
                    , [Ticket_2]
                    , [Ticket_3]
                    , [Ticket_4]
                    , [Ticket_5]
                    , [Charge_1]
                    , [Charge_2]
                    , [Charge_3]
                    , [Charge_4]
                    , [Charge_5]
                )
            ) as Pvt

            ;WITH SolicitorCTE AS
            (
                SELECT 
                    [People].Name AS SolicitorName
                    , SelectedFiles.FileId
                FROM 
                    #PivotedFile SelectedFiles
                    INNER JOIN [People2File]
                        ON [People2File].FileId = SelectedFiles.FileId
                    INNER JOIN [Role2Lexicon]
                        ON [Role2Lexicon].RoleId = [People2File].RoleId
                        AND [Role2Lexicon].Label = 'Solicitor'
                    INNER JOIN [People]
                        ON [People].Id = [People2File].PeopleId
            )
            , ArrestingOfficerCTE AS
            (
                SELECT 
                    ROW_NUMBER() OVER(PARTITION BY SelectionFile.Id ORDER BY [People].InvertedName ASC) AS RowNumber
                    , [People].Name AS ArrestingOfficerName
                    , [People].CompanyName AS ArrestingOfficerCompany
                    , SelectedFiles.FileId
                FROM 
                    #PivotedFile SelectedFiles
                    INNER JOIN [People2File]
                        ON [People2File].FileId = SelectedFiles.FileId
                    INNER JOIN [Role2Lexicon]
                        ON [Role2Lexicon].RoleId = [People2File].RoleId
                        AND [Role2Lexicon].Label = 'Arresting Officer'
                    INNER JOIN [People]
                        ON [People].Id = [People2File].PeopleId
            )
            SELECT 
                SelectedFiles.Id
                -- [Replace with any other columns that you selected from DOACTE you want to propagate to the end.]
                , COALESCE(ArrestingOfficerCTE.ArrestingOfficerCompany, 'NULL') AS ArrestingOfficerCompany
                , COALESCE(ArrestingOfficerCTE.ArrestingOfficerName, 'NULL') AS ArrestingOfficerName
                , SolicitorCTE.SolicitorName
                , SelectedFiles.[Date_Arrest]
                , dbo.GetImagebyId(SelectedFiles.[Graphic_Client]) as Photo
                , SelectedFiles.[Ticket_1]
                , SelectedFiles.[Ticket_2]
                , SelectedFiles.[Ticket_3]
                , SelectedFiles.[Ticket_4]
                , SelectedFiles.[Ticket_5]
                , SelectedFiles.[Charge_1]
                , SelectedFiles.[Charge_2]
                , SelectedFiles.[Charge_3]
                , SelectedFiles.[Charge_4]
                , SelectedFiles.[Charge_5]
            FROM #PivotedFile SelectedFiles
                LEFT JOIN SolicitorCTE
                    ON SelectedFiles.FileId = SolicitorCTE.FileId
                LEFT JOIN ArrestingOfficerCTE
                    ON SelectedFiles.FileId = ArrestingOfficerCTE.FileId
                    AND ArrestingOfficerCTE.RowNumber = 1

        DROP TABLE #SelectionFile
        DROP TABLE #PivotedFile
        END
    ELSE
        DELETE SelectionCache 
        WHERE 
            UUID = @UUID
            AND TableCode = @TableCode
    END
END

(如果您使用它,请阅读-- [Replace...]评论。